From 1527b076ae2cb6a9c590a02725ed39399fcad1cf Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 22 Jun 2023 10:24:35 +0200 Subject: [PATCH 0001/3445] spi: zynqmp-gqspi: fix clock imbalance on probe failure Make sure that the device is not runtime suspended before explicitly disabling the clocks on probe failure and on driver unbind to avoid a clock enable-count imbalance. Fixes: 9e3a000362ae ("spi: zynqmp: Add pm runtime support") Cc: stable@vger.kernel.org # 4.19 Cc: Naga Sureshkumar Relli Cc: Shubhrajyoti Datta Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/Message-Id: <20230622082435.7873-1-johan+linaro@kernel.org> Signed-off-by: Mark Brown --- drivers/spi/spi-zynqmp-gqspi.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index fb2ca9b90eabf..c309dedfd6020 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -1342,9 +1342,9 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) return 0; clk_dis_all: - pm_runtime_put_sync(&pdev->dev); - pm_runtime_set_suspended(&pdev->dev); pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); clk_disable_unprepare(xqspi->refclk); clk_dis_pclk: clk_disable_unprepare(xqspi->pclk); @@ -1368,11 +1368,15 @@ static void zynqmp_qspi_remove(struct platform_device *pdev) { struct zynqmp_qspi *xqspi = platform_get_drvdata(pdev); + pm_runtime_get_sync(&pdev->dev); + zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, 0x0); + + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); clk_disable_unprepare(xqspi->refclk); clk_disable_unprepare(xqspi->pclk); - pm_runtime_set_suspended(&pdev->dev); - pm_runtime_disable(&pdev->dev); } MODULE_DEVICE_TABLE(of, zynqmp_qspi_of_match); -- GitLab From bac6eb7235ab2efb4c0391c9572f9fc796aef22b Mon Sep 17 00:00:00 2001 From: Andreas Helbech Kleist Date: Wed, 5 Jul 2023 11:59:22 -0700 Subject: [PATCH 0002/3445] Input: exc3000 - add ACPI support for EXC80H60 EXC80H60 is used in Ambu aBox2 with ACPI _HID "EGA00001". Snippet of from "apcidump -b; iasl ssdt2.dat" on target: Device (TPL2) { Name (HID2, Zero) Name (_HID, "EGA00001") // _HID: Hardware ID Name (_CID, "PNP0C50" /* HID Protocol Device (I2C bus) */) // _CID: Compatible ID Name (_S0W, 0x04) // _S0W: S0 Device Wake State Name (SBFB, ResourceTemplate () Signed-off-by: Andreas Helbech Kleist Link: https://lore.kernel.org/r/20230705091817.1300928-1-andreaskleist@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/exc3000.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/input/touchscreen/exc3000.c b/drivers/input/touchscreen/exc3000.c index 4af4c1e5d0da2..66ed2eaa6dcb8 100644 --- a/drivers/input/touchscreen/exc3000.c +++ b/drivers/input/touchscreen/exc3000.c @@ -7,6 +7,7 @@ * minimal implementation based on egalax_ts.c and egalax_i2c.c */ +#include #include #include #include @@ -454,10 +455,19 @@ static const struct of_device_id exc3000_of_match[] = { MODULE_DEVICE_TABLE(of, exc3000_of_match); #endif +#ifdef CONFIG_ACPI +static const struct acpi_device_id exc3000_acpi_match[] = { + { "EGA00001", .driver_data = (kernel_ulong_t)&exc3000_info[EETI_EXC80H60] }, + { } +}; +MODULE_DEVICE_TABLE(acpi, exc3000_acpi_match); +#endif + static struct i2c_driver exc3000_driver = { .driver = { .name = "exc3000", .of_match_table = of_match_ptr(exc3000_of_match), + .acpi_match_table = ACPI_PTR(exc3000_acpi_match), }, .id_table = exc3000_id, .probe = exc3000_probe, -- GitLab From afbc67a90c7ccef304796af15477b43de5555b07 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 5 Jul 2023 12:26:19 -0700 Subject: [PATCH 0003/3445] Input: cpcap-pwrbutton - remove initial kernel-doc notation Change the beginning "/**" in the file to "/*" since it is not a kernel-doc comment. This prevents a kernel-doc warning: drivers/input/misc/cpcap-pwrbutton.c:2: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst * CPCAP Power Button Input Driver Signed-off-by: Randy Dunlap Reviewed-by: Sebastian Reichel Link: https://lore.kernel.org/r/20230703230005.14877-1-rdunlap@infradead.org Signed-off-by: Dmitry Torokhov --- drivers/input/misc/cpcap-pwrbutton.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/misc/cpcap-pwrbutton.c b/drivers/input/misc/cpcap-pwrbutton.c index 879790bbf9fe2..5aff5a7d6a35c 100644 --- a/drivers/input/misc/cpcap-pwrbutton.c +++ b/drivers/input/misc/cpcap-pwrbutton.c @@ -1,4 +1,4 @@ -/** +/* * CPCAP Power Button Input Driver * * Copyright (C) 2017 Sebastian Reichel -- GitLab From 2479191c30fe90c368fd6c8842e9846959466ccd Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Wed, 5 Jul 2023 14:49:36 -0700 Subject: [PATCH 0004/3445] Input: cpcap-pwrbutton - replace GPLv2 boilerplate with SPDX Replace the GPLv2 boilerplate text with a nice and short SPDX header. Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20230705212231.631525-1-sre@kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/misc/cpcap-pwrbutton.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/input/misc/cpcap-pwrbutton.c b/drivers/input/misc/cpcap-pwrbutton.c index 5aff5a7d6a35c..85cddb84717ae 100644 --- a/drivers/input/misc/cpcap-pwrbutton.c +++ b/drivers/input/misc/cpcap-pwrbutton.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * CPCAP Power Button Input Driver * * Copyright (C) 2017 Sebastian Reichel - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include -- GitLab From 650cda2ce25f08e8fae391b3ba6be27e7296c6a5 Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Wed, 5 Jul 2023 14:56:28 -0700 Subject: [PATCH 0005/3445] Input: gameport - add ISA and HAS_IOPORT dependencies In a future patch HAS_IOPORT=n will result in inb()/outb() and friends not being declared. As ISA already implies HAS_IOPORT we can simply add this dependency and guard sections of code using inb()/outb() as alternative access methods. Co-developed-by: Arnd Bergmann Signed-off-by: Arnd Bergmann Signed-off-by: Niklas Schnelle Link: https://lore.kernel.org/r/20230703152355.3897456-2-schnelle@linux.ibm.com Signed-off-by: Dmitry Torokhov --- drivers/input/gameport/Kconfig | 4 +++- drivers/input/gameport/gameport.c | 26 +++++++++++++++++++++----- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/input/gameport/Kconfig b/drivers/input/gameport/Kconfig index 5a2c2fb3217d5..fe73b26e647a1 100644 --- a/drivers/input/gameport/Kconfig +++ b/drivers/input/gameport/Kconfig @@ -25,6 +25,7 @@ if GAMEPORT config GAMEPORT_NS558 tristate "Classic ISA and PnP gameport support" + depends on ISA help Say Y here if you have an ISA or PnP gameport. @@ -35,6 +36,7 @@ config GAMEPORT_NS558 config GAMEPORT_L4 tristate "PDPI Lightning 4 gamecard support" + depends on ISA help Say Y here if you have a PDPI Lightning 4 gamecard. @@ -53,7 +55,7 @@ config GAMEPORT_EMU10K1 config GAMEPORT_FM801 tristate "ForteMedia FM801 gameport support" - depends on PCI + depends on PCI && HAS_IOPORT help Say Y here if you have ForteMedia FM801 PCI audio controller (Abit AU10, Genius Sound Maker, HP Workstation zx2000, diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index a1443320b4195..34f416a3ebcb7 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -519,12 +519,32 @@ EXPORT_SYMBOL(gameport_set_phys); static void gameport_default_trigger(struct gameport *gameport) { +#ifdef CONFIG_HAS_IOPORT outb(0xff, gameport->io); +#endif } static unsigned char gameport_default_read(struct gameport *gameport) { +#ifdef CONFIG_HAS_IOPORT return inb(gameport->io); +#else + return 0xff; +#endif +} + +static void gameport_setup_default_handlers(struct gameport *gameport) +{ + if ((!gameport->trigger || !gameport->read) && + !IS_ENABLED(CONFIG_HAS_IOPORT)) + dev_err(&gameport->dev, + "I/O port access is required for %s (%s) but is not available\n", + gameport->phys, gameport->name); + + if (!gameport->trigger) + gameport->trigger = gameport_default_trigger; + if (!gameport->read) + gameport->read = gameport_default_read; } /* @@ -545,11 +565,7 @@ static void gameport_init_port(struct gameport *gameport) if (gameport->parent) gameport->dev.parent = &gameport->parent->dev; - if (!gameport->trigger) - gameport->trigger = gameport_default_trigger; - if (!gameport->read) - gameport->read = gameport_default_read; - + gameport_setup_default_handlers(gameport); INIT_LIST_HEAD(&gameport->node); spin_lock_init(&gameport->timer_lock); timer_setup(&gameport->poll_timer, gameport_run_poll_handler, 0); -- GitLab From 1680ac7a5ad578d7acf819912557ceea4b4a5a88 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 7 Jul 2023 16:18:29 -0700 Subject: [PATCH 0006/3445] Input: gameport - use IS_REACHABLE() instead of open-coding it Replace an open-coded preprocessor conditional with an equivalent helper. Reviewed-by: Randy Dunlap Link: https://lore.kernel.org/r/ZKYLLmsdCH0Gp7TO@google.com Signed-off-by: Dmitry Torokhov --- include/linux/gameport.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/gameport.h b/include/linux/gameport.h index 0a221e768ea4f..07e370113b2b6 100644 --- a/include/linux/gameport.h +++ b/include/linux/gameport.h @@ -63,7 +63,7 @@ struct gameport_driver { int gameport_open(struct gameport *gameport, struct gameport_driver *drv, int mode); void gameport_close(struct gameport *gameport); -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#if IS_REACHABLE(CONFIG_GAMEPORT) void __gameport_register_port(struct gameport *gameport, struct module *owner); /* use a define to avoid include chaining to get THIS_MODULE */ -- GitLab From 05e6329443734a2a0aefb845d74375081d6626b6 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 7 Jul 2023 10:34:41 -0700 Subject: [PATCH 0007/3445] Input: xpad - fix support for some third-party controllers Some third-party controllers, such as the HORPIAD FPS for Nintendo Switch and Gamesir-G3w, require a specific packet that the first-party XInput driver sends before it will start sending reports. It's not currently known what this packet does, but since the first-party driver always sends it's unlikely that this could cause issues with existing controllers. Co-authored-by: Andrey Smirnov Signed-off-by: Vicki Pfau Link: https://lore.kernel.org/r/20230607012812.379640-2-vi@endrift.com Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 5d6a25b42bf90..745047215e425 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -264,6 +264,7 @@ static const struct xpad_device { { 0x0f0d, 0x0067, "HORIPAD ONE", 0, XTYPE_XBOXONE }, { 0x0f0d, 0x0078, "Hori Real Arcade Pro V Kai Xbox One", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, { 0x0f0d, 0x00c5, "Hori Fighting Commander ONE", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, + { 0x0f0d, 0x00dc, "HORIPAD FPS for Nintendo Switch", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0f30, 0x010b, "Philips Recoil", 0, XTYPE_XBOX }, { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX }, { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX }, @@ -1720,6 +1721,27 @@ static int xpad_start_input(struct usb_xpad *xpad) return error; } } + if (xpad->xtype == XTYPE_XBOX360) { + /* + * Some third-party controllers Xbox 360-style controllers + * require this message to finish initialization. + */ + u8 dummy[20]; + + error = usb_control_msg_recv(xpad->udev, 0, + /* bRequest */ 0x01, + /* bmRequestType */ + USB_TYPE_VENDOR | USB_DIR_IN | + USB_RECIP_INTERFACE, + /* wValue */ 0x100, + /* wIndex */ 0x00, + dummy, sizeof(dummy), + 25, GFP_KERNEL); + if (error) + dev_warn(&xpad->dev->dev, + "unable to receive magic message: %d\n", + error); + } return 0; } -- GitLab From 1dfd41115f186bf0c7a9b3f0dd39a0985d828d65 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 7 Jul 2023 15:10:59 -0700 Subject: [PATCH 0008/3445] Input: xpad - add GameSir VID for Xbox One controllers Signed-off-by: Sam Lantinga Signed-off-by: Vicki Pfau Link: https://lore.kernel.org/r/20230607012812.379640-3-vi@endrift.com Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 745047215e425..e0b6edb35b597 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -501,6 +501,7 @@ static const struct usb_device_id xpad_table[] = { XPAD_XBOX360_VENDOR(0x2f24), /* GameSir controllers */ XPAD_XBOX360_VENDOR(0x31e3), /* Wooting Keyboards */ XPAD_XBOX360_VENDOR(0x3285), /* Nacon GC-100 */ + XPAD_XBOXONE_VENDOR(0x3537), /* GameSir Controllers */ { } }; -- GitLab From 854d2233de0ac8ad37b71ec3698946054b22104c Mon Sep 17 00:00:00 2001 From: Jonathan Frederick Date: Fri, 7 Jul 2023 15:11:33 -0700 Subject: [PATCH 0009/3445] Input: xpad - add GameSir T4 Kaleid Controller support Add VID and PID to the xpad_device table to allow driver to use the GameSir T4 Kaleid Controller, which is XTYPE_XBOX360 compatible in xinput mode. Signed-off-by: Jonathan Frederick Link: https://lore.kernel.org/r/ZKeKSbP3faIPv5jB@dbj-hp-flip Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index e0b6edb35b597..c4bc0958471dc 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -367,6 +367,7 @@ static const struct xpad_device { { 0x31e3, 0x1300, "Wooting 60HE (AVR)", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1310, "Wooting 60HE (ARM)", 0, XTYPE_XBOX360 }, { 0x3285, 0x0607, "Nacon GC-100", 0, XTYPE_XBOX360 }, + { 0x3537, 0x1004, "GameSir T4 Kaleid", 0, XTYPE_XBOX360 }, { 0x3767, 0x0101, "Fanatec Speedster 3 Forceshock Wheel", 0, XTYPE_XBOX }, { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX }, { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN } @@ -501,6 +502,7 @@ static const struct usb_device_id xpad_table[] = { XPAD_XBOX360_VENDOR(0x2f24), /* GameSir controllers */ XPAD_XBOX360_VENDOR(0x31e3), /* Wooting Keyboards */ XPAD_XBOX360_VENDOR(0x3285), /* Nacon GC-100 */ + XPAD_XBOX360_VENDOR(0x3537), /* GameSir Controllers */ XPAD_XBOXONE_VENDOR(0x3537), /* GameSir Controllers */ { } }; -- GitLab From ff785255699c78c1b2ca0b21f2ae4a3ea4163bb0 Mon Sep 17 00:00:00 2001 From: Mike Looijmans Date: Fri, 7 Jul 2023 16:28:07 -0700 Subject: [PATCH 0010/3445] dt-bindings: input: exc3000: support power supply regulators Add power supply regulator support to the exc3000 devices. Signed-off-by: Mike Looijmans Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230707131042.10795-1-mike.looijmans@topic.nl Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/touchscreen/eeti,exc3000.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/input/touchscreen/eeti,exc3000.yaml b/Documentation/devicetree/bindings/input/touchscreen/eeti,exc3000.yaml index 007adbc89c143..9dc25d30a0a89 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/eeti,exc3000.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/eeti,exc3000.yaml @@ -24,6 +24,8 @@ properties: maxItems: 1 reset-gpios: maxItems: 1 + vdd-supply: + description: Power supply regulator for the chip touchscreen-size-x: true touchscreen-size-y: true touchscreen-inverted-x: true -- GitLab From 0d384e5959dde12717419a3fd77ee62cc10f069f Mon Sep 17 00:00:00 2001 From: Mike Looijmans Date: Fri, 7 Jul 2023 16:29:15 -0700 Subject: [PATCH 0011/3445] Input: exc3000 - support power supply regulators Add power supply regulator support to the exc3000 devices. Signed-off-by: Mike Looijmans Link: https://lore.kernel.org/r/20230707131042.10795-2-mike.looijmans@topic.nl Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/exc3000.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/input/touchscreen/exc3000.c b/drivers/input/touchscreen/exc3000.c index 4af4c1e5d0da2..e3f6d21b3c1b3 100644 --- a/drivers/input/touchscreen/exc3000.c +++ b/drivers/input/touchscreen/exc3000.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -360,6 +361,12 @@ static int exc3000_probe(struct i2c_client *client) if (IS_ERR(data->reset)) return PTR_ERR(data->reset); + /* For proper reset sequence, enable power while reset asserted */ + error = devm_regulator_get_enable(&client->dev, "vdd"); + if (error && error != -ENODEV) + return dev_err_probe(&client->dev, error, + "failed to request vdd regulator\n"); + if (data->reset) { msleep(EXC3000_RESET_MS); gpiod_set_value_cansleep(data->reset, 0); -- GitLab From caec3d4416a2fbd7399556ba366da4d8fc05d9f5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:27:54 +0200 Subject: [PATCH 0012/3445] Input: gpio_keys_polled - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20230625162817.100397-2-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys_polled.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index c3937d2fc7446..ba00ecfbd343b 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -299,13 +299,9 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) NULL, GPIOD_IN, button->desc); if (IS_ERR(bdata->gpiod)) { - error = PTR_ERR(bdata->gpiod); - if (error != -EPROBE_DEFER) - dev_err(dev, - "failed to get gpio: %d\n", - error); fwnode_handle_put(child); - return error; + return dev_err_probe(dev, PTR_ERR(bdata->gpiod), + "failed to get gpio\n"); } } else if (gpio_is_valid(button->gpio)) { /* -- GitLab From c4834f4ad7fdc9002e7d3424bd7aed7a63f070be Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:27:55 +0200 Subject: [PATCH 0013/3445] Input: gpio-vibra - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20230625162817.100397-3-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/misc/gpio-vibra.c | 20 ++++++-------------- drivers/input/misc/pwm-beeper.c | 19 +++++-------------- 2 files changed, 11 insertions(+), 28 deletions(-) diff --git a/drivers/input/misc/gpio-vibra.c b/drivers/input/misc/gpio-vibra.c index 134a1309ba927..c1c3ba5960ddf 100644 --- a/drivers/input/misc/gpio-vibra.c +++ b/drivers/input/misc/gpio-vibra.c @@ -113,22 +113,14 @@ static int gpio_vibrator_probe(struct platform_device *pdev) return -ENOMEM; vibrator->vcc = devm_regulator_get(&pdev->dev, "vcc"); - err = PTR_ERR_OR_ZERO(vibrator->vcc); - if (err) { - if (err != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to request regulator: %d\n", - err); - return err; - } + if (IS_ERR(vibrator->vcc)) + return dev_err_probe(&pdev->dev, PTR_ERR(vibrator->vcc), + "Failed to request regulator\n"); vibrator->gpio = devm_gpiod_get(&pdev->dev, "enable", GPIOD_OUT_LOW); - err = PTR_ERR_OR_ZERO(vibrator->gpio); - if (err) { - if (err != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to request main gpio: %d\n", - err); - return err; - } + if (IS_ERR(vibrator->gpio)) + return dev_err_probe(&pdev->dev, PTR_ERR(vibrator->gpio), + "Failed to request main gpio\n"); INIT_WORK(&vibrator->play_work, gpio_vibrator_play_work); diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c index 3cf1812384e6a..1e731d8397c6f 100644 --- a/drivers/input/misc/pwm-beeper.c +++ b/drivers/input/misc/pwm-beeper.c @@ -132,13 +132,8 @@ static int pwm_beeper_probe(struct platform_device *pdev) return -ENOMEM; beeper->pwm = devm_pwm_get(dev, NULL); - if (IS_ERR(beeper->pwm)) { - error = PTR_ERR(beeper->pwm); - if (error != -EPROBE_DEFER) - dev_err(dev, "Failed to request PWM device: %d\n", - error); - return error; - } + if (IS_ERR(beeper->pwm)) + return dev_err_probe(dev, PTR_ERR(beeper->pwm), "Failed to request PWM device\n"); /* Sync up PWM state and ensure it is off. */ pwm_init_state(beeper->pwm, &state); @@ -151,13 +146,9 @@ static int pwm_beeper_probe(struct platform_device *pdev) } beeper->amplifier = devm_regulator_get(dev, "amp"); - if (IS_ERR(beeper->amplifier)) { - error = PTR_ERR(beeper->amplifier); - if (error != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'amp' regulator: %d\n", - error); - return error; - } + if (IS_ERR(beeper->amplifier)) + return dev_err_probe(dev, PTR_ERR(beeper->amplifier), + "Failed to get 'amp' regulator\n"); INIT_WORK(&beeper->work, pwm_beeper_work); -- GitLab From a07e68dff58bd536f9e909b007875726eade5c0e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:27:56 +0200 Subject: [PATCH 0014/3445] Input: pwm-vibra - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230625162817.100397-4-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/misc/pwm-vibra.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/drivers/input/misc/pwm-vibra.c b/drivers/input/misc/pwm-vibra.c index 2ba035299db87..a3cde30ee8d2b 100644 --- a/drivers/input/misc/pwm-vibra.c +++ b/drivers/input/misc/pwm-vibra.c @@ -140,32 +140,20 @@ static int pwm_vibrator_probe(struct platform_device *pdev) return -ENOMEM; vibrator->vcc = devm_regulator_get(&pdev->dev, "vcc"); - err = PTR_ERR_OR_ZERO(vibrator->vcc); - if (err) { - if (err != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to request regulator: %d\n", - err); - return err; - } + if (IS_ERR(vibrator->vcc)) + return dev_err_probe(&pdev->dev, PTR_ERR(vibrator->vcc), + "Failed to request regulator\n"); vibrator->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable", GPIOD_OUT_LOW); - err = PTR_ERR_OR_ZERO(vibrator->enable_gpio); - if (err) { - if (err != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to request enable gpio: %d\n", - err); - return err; - } + if (IS_ERR(vibrator->enable_gpio)) + return dev_err_probe(&pdev->dev, PTR_ERR(vibrator->enable_gpio), + "Failed to request enable gpio\n"); vibrator->pwm = devm_pwm_get(&pdev->dev, "enable"); - err = PTR_ERR_OR_ZERO(vibrator->pwm); - if (err) { - if (err != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to request main pwm: %d\n", - err); - return err; - } + if (IS_ERR(vibrator->pwm)) + return dev_err_probe(&pdev->dev, PTR_ERR(vibrator->pwm), + "Failed to request main pwm\n"); INIT_WORK(&vibrator->play_work, pwm_vibrator_play_work); -- GitLab From 1e402a15bc00201c1068596445ebfe98d60d1c58 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:27:57 +0200 Subject: [PATCH 0015/3445] Input: rotary_encoder - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230625162817.100397-5-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/misc/rotary_encoder.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 22ec620830653..fb3a34f8eccd2 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -236,12 +236,8 @@ static int rotary_encoder_probe(struct platform_device *pdev) device_property_read_bool(dev, "rotary-encoder,relative-axis"); encoder->gpios = devm_gpiod_get_array(dev, NULL, GPIOD_IN); - if (IS_ERR(encoder->gpios)) { - err = PTR_ERR(encoder->gpios); - if (err != -EPROBE_DEFER) - dev_err(dev, "unable to get gpios: %d\n", err); - return err; - } + if (IS_ERR(encoder->gpios)) + return dev_err_probe(dev, PTR_ERR(encoder->gpios), "unable to get gpios\n"); if (encoder->gpios->ndescs < 2) { dev_err(dev, "not enough gpios found\n"); return -EINVAL; -- GitLab From 50653e8fada2f92c07559e129199daaa3f760d00 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:27:58 +0200 Subject: [PATCH 0016/3445] Input: elan_i2c - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230625162817.100397-6-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c_core.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 0cff742302a9f..148a601396f92 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1221,13 +1221,8 @@ static int elan_probe(struct i2c_client *client) mutex_init(&data->sysfs_mutex); data->vcc = devm_regulator_get(dev, "vcc"); - if (IS_ERR(data->vcc)) { - error = PTR_ERR(data->vcc); - if (error != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'vcc' regulator: %d\n", - error); - return error; - } + if (IS_ERR(data->vcc)) + return dev_err_probe(dev, PTR_ERR(data->vcc), "Failed to get 'vcc' regulator\n"); error = regulator_enable(data->vcc); if (error) { -- GitLab From 2886c5b97c8f753eb4aff618ae78832718835151 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:27:59 +0200 Subject: [PATCH 0017/3445] Input: bu21013_ts - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Acked-by: Linus Walleij Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230625162817.100397-7-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/bu21013_ts.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c index 85332cfaa29dc..f811677a59f7a 100644 --- a/drivers/input/touchscreen/bu21013_ts.c +++ b/drivers/input/touchscreen/bu21013_ts.c @@ -495,12 +495,10 @@ static int bu21013_probe(struct i2c_client *client) /* Named "CS" on the chip, DT binding is "reset" */ ts->cs_gpiod = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); - error = PTR_ERR_OR_ZERO(ts->cs_gpiod); - if (error) { - if (error != -EPROBE_DEFER) - dev_err(&client->dev, "failed to get CS GPIO\n"); - return error; - } + if (IS_ERR(ts->cs_gpiod)) + return dev_err_probe(&client->dev, PTR_ERR(ts->cs_gpiod), + "failed to get CS GPIO\n"); + gpiod_set_consumer_name(ts->cs_gpiod, "BU21013 CS"); error = devm_add_action_or_reset(&client->dev, @@ -515,11 +513,8 @@ static int bu21013_probe(struct i2c_client *client) ts->int_gpiod = devm_gpiod_get_optional(&client->dev, "touch", GPIOD_IN); error = PTR_ERR_OR_ZERO(ts->int_gpiod); - if (error) { - if (error != -EPROBE_DEFER) - dev_err(&client->dev, "failed to get INT GPIO\n"); - return error; - } + if (error) + return dev_err_probe(&client->dev, error, "failed to get INT GPIO\n"); if (ts->int_gpiod) gpiod_set_consumer_name(ts->int_gpiod, "BU21013 INT"); -- GitLab From 64eb0f741ea2f4b73bcf30d66cf7d1c16593f581 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:28:00 +0200 Subject: [PATCH 0018/3445] Input: bu21029_ts - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230625162817.100397-8-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/bu21029_ts.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/input/touchscreen/bu21029_ts.c b/drivers/input/touchscreen/bu21029_ts.c index c8126d2efe95a..3d81ebe66b66c 100644 --- a/drivers/input/touchscreen/bu21029_ts.c +++ b/drivers/input/touchscreen/bu21029_ts.c @@ -359,23 +359,15 @@ static int bu21029_probe(struct i2c_client *client) } bu21029->vdd = devm_regulator_get(&client->dev, "vdd"); - if (IS_ERR(bu21029->vdd)) { - error = PTR_ERR(bu21029->vdd); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "failed to acquire 'vdd' supply: %d\n", error); - return error; - } + if (IS_ERR(bu21029->vdd)) + return dev_err_probe(&client->dev, PTR_ERR(bu21029->vdd), + "failed to acquire 'vdd' supply\n"); bu21029->reset_gpios = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(bu21029->reset_gpios)) { - error = PTR_ERR(bu21029->reset_gpios); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "failed to acquire 'reset' gpio: %d\n", error); - return error; - } + if (IS_ERR(bu21029->reset_gpios)) + return dev_err_probe(&client->dev, PTR_ERR(bu21029->reset_gpios), + "failed to acquire 'reset' gpio\n"); in_dev = devm_input_allocate_device(&client->dev); if (!in_dev) { -- GitLab From 0d9025a46b2f218c52f2216afabc24537b1e5187 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:28:01 +0200 Subject: [PATCH 0019/3445] Input: chipone_icn8318 - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230625162817.100397-9-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/chipone_icn8318.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/input/touchscreen/chipone_icn8318.c b/drivers/input/touchscreen/chipone_icn8318.c index 9fbeaf17f00b7..d6876d10b2528 100644 --- a/drivers/input/touchscreen/chipone_icn8318.c +++ b/drivers/input/touchscreen/chipone_icn8318.c @@ -191,12 +191,8 @@ static int icn8318_probe(struct i2c_client *client) return -ENOMEM; data->wake_gpio = devm_gpiod_get(dev, "wake", GPIOD_OUT_LOW); - if (IS_ERR(data->wake_gpio)) { - error = PTR_ERR(data->wake_gpio); - if (error != -EPROBE_DEFER) - dev_err(dev, "Error getting wake gpio: %d\n", error); - return error; - } + if (IS_ERR(data->wake_gpio)) + return dev_err_probe(dev, PTR_ERR(data->wake_gpio), "Error getting wake gpio\n"); input = devm_input_allocate_device(dev); if (!input) -- GitLab From 8d3b0460e8ef68f893d9f1f6f5da37d67be33b89 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:28:02 +0200 Subject: [PATCH 0020/3445] Input: cy8ctma140 - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Acked-by: Linus Walleij Link: https://lore.kernel.org/r/20230625162817.100397-10-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/cy8ctma140.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/input/touchscreen/cy8ctma140.c b/drivers/input/touchscreen/cy8ctma140.c index 967ecde23e83f..ea3895167b82e 100644 --- a/drivers/input/touchscreen/cy8ctma140.c +++ b/drivers/input/touchscreen/cy8ctma140.c @@ -258,12 +258,8 @@ static int cy8ctma140_probe(struct i2c_client *client) ts->regulators[1].supply = "vdd"; error = devm_regulator_bulk_get(dev, ARRAY_SIZE(ts->regulators), ts->regulators); - if (error) { - if (error != -EPROBE_DEFER) - dev_err(dev, "Failed to get regulators %d\n", - error); - return error; - } + if (error) + return dev_err_probe(dev, error, "Failed to get regulators\n"); error = cy8ctma140_power_up(ts); if (error) -- GitLab From 14e5f4db20096e0be30b8a567e92b726f4d86ac0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:28:03 +0200 Subject: [PATCH 0021/3445] Input: edf-ft5x06 - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230625162817.100397-11-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/edt-ft5x06.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 795c7dad22bfb..457d53337fbb3 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -1168,13 +1168,9 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) tsdata->max_support_points = chip_data->max_support_points; tsdata->vcc = devm_regulator_get(&client->dev, "vcc"); - if (IS_ERR(tsdata->vcc)) { - error = PTR_ERR(tsdata->vcc); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "failed to request regulator: %d\n", error); - return error; - } + if (IS_ERR(tsdata->vcc)) + return dev_err_probe(&client->dev, PTR_ERR(tsdata->vcc), + "failed to request regulator\n"); tsdata->iovcc = devm_regulator_get(&client->dev, "iovcc"); if (IS_ERR(tsdata->iovcc)) { -- GitLab From d9efc285f75e7f6028ff3b87f0169a0decfdc36b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:28:04 +0200 Subject: [PATCH 0022/3445] Input: ektf2127 - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230625162817.100397-12-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ektf2127.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/input/touchscreen/ektf2127.c b/drivers/input/touchscreen/ektf2127.c index fd8724a3c19fd..cc3103b9cbfba 100644 --- a/drivers/input/touchscreen/ektf2127.c +++ b/drivers/input/touchscreen/ektf2127.c @@ -264,12 +264,8 @@ static int ektf2127_probe(struct i2c_client *client) /* This requests the gpio *and* turns on the touchscreen controller */ ts->power_gpios = devm_gpiod_get(dev, "power", GPIOD_OUT_HIGH); - if (IS_ERR(ts->power_gpios)) { - error = PTR_ERR(ts->power_gpios); - if (error != -EPROBE_DEFER) - dev_err(dev, "Error getting power gpio: %d\n", error); - return error; - } + if (IS_ERR(ts->power_gpios)) + return dev_err_probe(dev, PTR_ERR(ts->power_gpios), "Error getting power gpio\n"); input = devm_input_allocate_device(dev); if (!input) -- GitLab From e89f0de5da36ff28182cba576649d893e2776916 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:28:05 +0200 Subject: [PATCH 0023/3445] Input: elants_i2c - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230625162817.100397-13-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/elants_i2c.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index 2da1db64126d1..a1af3de9f3109 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -1438,24 +1438,14 @@ static int elants_i2c_probe(struct i2c_client *client) i2c_set_clientdata(client, ts); ts->vcc33 = devm_regulator_get(&client->dev, "vcc33"); - if (IS_ERR(ts->vcc33)) { - error = PTR_ERR(ts->vcc33); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "Failed to get 'vcc33' regulator: %d\n", - error); - return error; - } + if (IS_ERR(ts->vcc33)) + return dev_err_probe(&client->dev, PTR_ERR(ts->vcc33), + "Failed to get 'vcc33' regulator\n"); ts->vccio = devm_regulator_get(&client->dev, "vccio"); - if (IS_ERR(ts->vccio)) { - error = PTR_ERR(ts->vccio); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "Failed to get 'vccio' regulator: %d\n", - error); - return error; - } + if (IS_ERR(ts->vccio)) + return dev_err_probe(&client->dev, PTR_ERR(ts->vccio), + "Failed to get 'vccio' regulator\n"); ts->reset_gpio = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(ts->reset_gpio)) { -- GitLab From bf2ae3897f7165e6ff0f5cfded7211cf08d5d855 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:28:06 +0200 Subject: [PATCH 0024/3445] Input: goodix - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230625162817.100397-14-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/goodix.c | 40 ++++++++---------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index f6beef5231403..d88e1222dd931 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -927,7 +927,6 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts) */ static int goodix_get_gpio_config(struct goodix_ts_data *ts) { - int error; struct device *dev; struct gpio_desc *gpiod; bool added_acpi_mappings = false; @@ -943,33 +942,20 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts) ts->gpiod_rst_flags = GPIOD_IN; ts->avdd28 = devm_regulator_get(dev, "AVDD28"); - if (IS_ERR(ts->avdd28)) { - error = PTR_ERR(ts->avdd28); - if (error != -EPROBE_DEFER) - dev_err(dev, - "Failed to get AVDD28 regulator: %d\n", error); - return error; - } + if (IS_ERR(ts->avdd28)) + return dev_err_probe(dev, PTR_ERR(ts->avdd28), "Failed to get AVDD28 regulator\n"); ts->vddio = devm_regulator_get(dev, "VDDIO"); - if (IS_ERR(ts->vddio)) { - error = PTR_ERR(ts->vddio); - if (error != -EPROBE_DEFER) - dev_err(dev, - "Failed to get VDDIO regulator: %d\n", error); - return error; - } + if (IS_ERR(ts->vddio)) + return dev_err_probe(dev, PTR_ERR(ts->vddio), "Failed to get VDDIO regulator\n"); retry_get_irq_gpio: /* Get the interrupt GPIO pin number */ gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_INT_NAME, GPIOD_IN); - if (IS_ERR(gpiod)) { - error = PTR_ERR(gpiod); - if (error != -EPROBE_DEFER) - dev_err(dev, "Failed to get %s GPIO: %d\n", - GOODIX_GPIO_INT_NAME, error); - return error; - } + if (IS_ERR(gpiod)) + return dev_err_probe(dev, PTR_ERR(gpiod), "Failed to get %s GPIO\n", + GOODIX_GPIO_INT_NAME); + if (!gpiod && has_acpi_companion(dev) && !added_acpi_mappings) { added_acpi_mappings = true; if (goodix_add_acpi_gpio_mappings(ts) == 0) @@ -980,13 +966,9 @@ retry_get_irq_gpio: /* Get the reset line GPIO pin number */ gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, ts->gpiod_rst_flags); - if (IS_ERR(gpiod)) { - error = PTR_ERR(gpiod); - if (error != -EPROBE_DEFER) - dev_err(dev, "Failed to get %s GPIO: %d\n", - GOODIX_GPIO_RST_NAME, error); - return error; - } + if (IS_ERR(gpiod)) + return dev_err_probe(dev, PTR_ERR(gpiod), "Failed to get %s GPIO\n", + GOODIX_GPIO_RST_NAME); ts->gpiod_rst = gpiod; -- GitLab From 10ba628ee0af65796acce5f888598e42f5bca309 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:28:07 +0200 Subject: [PATCH 0025/3445] Input: melfas_mip4 - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230625162817.100397-15-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/melfas_mip4.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c index 32896e5085bdc..2ac4483fbc258 100644 --- a/drivers/input/touchscreen/melfas_mip4.c +++ b/drivers/input/touchscreen/melfas_mip4.c @@ -1451,13 +1451,8 @@ static int mip4_probe(struct i2c_client *client) ts->gpio_ce = devm_gpiod_get_optional(&client->dev, "ce", GPIOD_OUT_LOW); - if (IS_ERR(ts->gpio_ce)) { - error = PTR_ERR(ts->gpio_ce); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "Failed to get gpio: %d\n", error); - return error; - } + if (IS_ERR(ts->gpio_ce)) + return dev_err_probe(&client->dev, PTR_ERR(ts->gpio_ce), "Failed to get gpio\n"); error = mip4_power_on(ts); if (error) -- GitLab From e32825c47042d4e727b867bb98d679bb5cc74f87 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:28:08 +0200 Subject: [PATCH 0026/3445] Input: pixcir_i2c_ts - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230625162817.100397-16-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/pixcir_i2c_ts.c | 38 +++++++---------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 554e179c2e487..0b4576091dacc 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -515,41 +515,27 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client) input_set_drvdata(input, tsdata); tsdata->gpio_attb = devm_gpiod_get(dev, "attb", GPIOD_IN); - if (IS_ERR(tsdata->gpio_attb)) { - error = PTR_ERR(tsdata->gpio_attb); - if (error != -EPROBE_DEFER) - dev_err(dev, "Failed to request ATTB gpio: %d\n", - error); - return error; - } + if (IS_ERR(tsdata->gpio_attb)) + return dev_err_probe(dev, PTR_ERR(tsdata->gpio_attb), + "Failed to request ATTB gpio\n"); tsdata->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(tsdata->gpio_reset)) { - error = PTR_ERR(tsdata->gpio_reset); - if (error != -EPROBE_DEFER) - dev_err(dev, "Failed to request RESET gpio: %d\n", - error); - return error; - } + if (IS_ERR(tsdata->gpio_reset)) + return dev_err_probe(dev, PTR_ERR(tsdata->gpio_reset), + "Failed to request RESET gpio\n"); tsdata->gpio_wake = devm_gpiod_get_optional(dev, "wake", GPIOD_OUT_HIGH); - if (IS_ERR(tsdata->gpio_wake)) { - error = PTR_ERR(tsdata->gpio_wake); - if (error != -EPROBE_DEFER) - dev_err(dev, "Failed to get wake gpio: %d\n", error); - return error; - } + if (IS_ERR(tsdata->gpio_wake)) + return dev_err_probe(dev, PTR_ERR(tsdata->gpio_wake), + "Failed to get wake gpio\n"); tsdata->gpio_enable = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); - if (IS_ERR(tsdata->gpio_enable)) { - error = PTR_ERR(tsdata->gpio_enable); - if (error != -EPROBE_DEFER) - dev_err(dev, "Failed to get enable gpio: %d\n", error); - return error; - } + if (IS_ERR(tsdata->gpio_enable)) + return dev_err_probe(dev, PTR_ERR(tsdata->gpio_enable), + "Failed to get enable gpio\n"); if (tsdata->gpio_enable) msleep(100); -- GitLab From ca0d9997f5437ddb754b8743ff15d853d474371e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:28:09 +0200 Subject: [PATCH 0027/3445] Input: raydium_i2c_ts - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230625162817.100397-17-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/raydium_i2c_ts.c | 30 +++++++--------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c index 76e7d62d58702..78dd3059d585a 100644 --- a/drivers/input/touchscreen/raydium_i2c_ts.c +++ b/drivers/input/touchscreen/raydium_i2c_ts.c @@ -1087,32 +1087,20 @@ static int raydium_i2c_probe(struct i2c_client *client) i2c_set_clientdata(client, ts); ts->avdd = devm_regulator_get(&client->dev, "avdd"); - if (IS_ERR(ts->avdd)) { - error = PTR_ERR(ts->avdd); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "Failed to get 'avdd' regulator: %d\n", error); - return error; - } + if (IS_ERR(ts->avdd)) + return dev_err_probe(&client->dev, PTR_ERR(ts->avdd), + "Failed to get 'avdd' regulator\n"); ts->vccio = devm_regulator_get(&client->dev, "vccio"); - if (IS_ERR(ts->vccio)) { - error = PTR_ERR(ts->vccio); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "Failed to get 'vccio' regulator: %d\n", error); - return error; - } + if (IS_ERR(ts->vccio)) + return dev_err_probe(&client->dev, PTR_ERR(ts->vccio), + "Failed to get 'vccio' regulator\n"); ts->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(ts->reset_gpio)) { - error = PTR_ERR(ts->reset_gpio); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "failed to get reset gpio: %d\n", error); - return error; - } + if (IS_ERR(ts->reset_gpio)) + return dev_err_probe(&client->dev, PTR_ERR(ts->reset_gpio), + "Failed to get reset gpio\n"); error = raydium_i2c_power_on(ts); if (error) -- GitLab From 17d981fa707ef6f212dda17d1ec64a4a360c91a7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:28:10 +0200 Subject: [PATCH 0028/3445] Input: resistive-adc-touch - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230625162817.100397-18-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/resistive-adc-touch.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/input/touchscreen/resistive-adc-touch.c b/drivers/input/touchscreen/resistive-adc-touch.c index 6f754a8d30b11..7e761ec73273b 100644 --- a/drivers/input/touchscreen/resistive-adc-touch.c +++ b/drivers/input/touchscreen/resistive-adc-touch.c @@ -210,12 +210,8 @@ static int grts_probe(struct platform_device *pdev) /* get the channels from IIO device */ st->iio_chans = devm_iio_channel_get_all(dev); - if (IS_ERR(st->iio_chans)) { - error = PTR_ERR(st->iio_chans); - if (error != -EPROBE_DEFER) - dev_err(dev, "can't get iio channels.\n"); - return error; - } + if (IS_ERR(st->iio_chans)) + return dev_err_probe(dev, PTR_ERR(st->iio_chans), "can't get iio channels\n"); if (!device_property_present(dev, "io-channel-names")) return -ENODEV; -- GitLab From 21142c1cb29048f536700b833be1b2806fff3ef7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:28:11 +0200 Subject: [PATCH 0029/3445] Input: silead - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230625162817.100397-19-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/silead.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c index 9e28f962e059d..62f562ad50263 100644 --- a/drivers/input/touchscreen/silead.c +++ b/drivers/input/touchscreen/silead.c @@ -706,11 +706,9 @@ static int silead_ts_probe(struct i2c_client *client) /* Power GPIO pin */ data->gpio_power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW); - if (IS_ERR(data->gpio_power)) { - if (PTR_ERR(data->gpio_power) != -EPROBE_DEFER) - dev_err(dev, "Shutdown GPIO request failed\n"); - return PTR_ERR(data->gpio_power); - } + if (IS_ERR(data->gpio_power)) + return dev_err_probe(dev, PTR_ERR(data->gpio_power), + "Shutdown GPIO request failed\n"); error = silead_ts_setup(client); if (error) -- GitLab From d3aeb44cc6b21944c31b07728516924e9cb10825 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:28:12 +0200 Subject: [PATCH 0030/3445] Input: sis_i2c - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230625162817.100397-20-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/sis_i2c.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/input/touchscreen/sis_i2c.c b/drivers/input/touchscreen/sis_i2c.c index 426564d0fc39a..ed56cb546f393 100644 --- a/drivers/input/touchscreen/sis_i2c.c +++ b/drivers/input/touchscreen/sis_i2c.c @@ -310,23 +310,15 @@ static int sis_ts_probe(struct i2c_client *client) ts->attn_gpio = devm_gpiod_get_optional(&client->dev, "attn", GPIOD_IN); - if (IS_ERR(ts->attn_gpio)) { - error = PTR_ERR(ts->attn_gpio); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "Failed to get attention GPIO: %d\n", error); - return error; - } + if (IS_ERR(ts->attn_gpio)) + return dev_err_probe(&client->dev, PTR_ERR(ts->attn_gpio), + "Failed to get attention GPIO\n"); ts->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(ts->reset_gpio)) { - error = PTR_ERR(ts->reset_gpio); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "Failed to get reset GPIO: %d\n", error); - return error; - } + if (IS_ERR(ts->reset_gpio)) + return dev_err_probe(&client->dev, PTR_ERR(ts->reset_gpio), + "Failed to get reset GPIO\n"); sis_ts_reset(ts); -- GitLab From d08149c13aa27bd2c0884915dea0eb1a171e1c2e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:28:13 +0200 Subject: [PATCH 0031/3445] Input: surface3_spi - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230625162817.100397-21-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/surface3_spi.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c index 31d140248f2e9..7efbcd0fde4fc 100644 --- a/drivers/input/touchscreen/surface3_spi.c +++ b/drivers/input/touchscreen/surface3_spi.c @@ -221,7 +221,6 @@ static void surface3_spi_power(struct surface3_ts_data *data, bool on) */ static int surface3_spi_get_gpio_config(struct surface3_ts_data *data) { - int error; struct device *dev; struct gpio_desc *gpiod; int i; @@ -231,15 +230,9 @@ static int surface3_spi_get_gpio_config(struct surface3_ts_data *data) /* Get the reset lines GPIO pin number */ for (i = 0; i < 2; i++) { gpiod = devm_gpiod_get_index(dev, NULL, i, GPIOD_OUT_LOW); - if (IS_ERR(gpiod)) { - error = PTR_ERR(gpiod); - if (error != -EPROBE_DEFER) - dev_err(dev, - "Failed to get power GPIO %d: %d\n", - i, - error); - return error; - } + if (IS_ERR(gpiod)) + return dev_err_probe(dev, PTR_ERR(gpiod), + "Failed to get power GPIO %d\n", i); data->gpiod_rst[i] = gpiod; } -- GitLab From 337ac36c3bc0be71e73322cbbc0d6a8b8a2c05f6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:28:14 +0200 Subject: [PATCH 0032/3445] Input: sx8643 - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230625162817.100397-22-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/sx8654.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c index 0293c493bc79f..f5c5881cef6bc 100644 --- a/drivers/input/touchscreen/sx8654.c +++ b/drivers/input/touchscreen/sx8654.c @@ -323,13 +323,9 @@ static int sx8654_probe(struct i2c_client *client) sx8654->gpio_reset = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(sx8654->gpio_reset)) { - error = PTR_ERR(sx8654->gpio_reset); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, "unable to get reset-gpio: %d\n", - error); - return error; - } + if (IS_ERR(sx8654->gpio_reset)) + return dev_err_probe(&client->dev, PTR_ERR(sx8654->gpio_reset), + "unable to get reset-gpio\n"); dev_dbg(&client->dev, "got GPIO reset pin\n"); sx8654->data = device_get_match_data(&client->dev); -- GitLab From a2c795b696b20ebc56462a2fbbc0d612ef265389 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:28:15 +0200 Subject: [PATCH 0033/3445] Input: bcm-keypad - simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe() and devm_clk_get_optional(). Less code and the error value gets printed. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230625162817.100397-23-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/bcm-keypad.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/input/keyboard/bcm-keypad.c b/drivers/input/keyboard/bcm-keypad.c index 56a919ec23b52..05b09066df849 100644 --- a/drivers/input/keyboard/bcm-keypad.c +++ b/drivers/input/keyboard/bcm-keypad.c @@ -365,17 +365,11 @@ static int bcm_kp_probe(struct platform_device *pdev) return PTR_ERR(kp->base); /* Enable clock */ - kp->clk = devm_clk_get(&pdev->dev, "peri_clk"); + kp->clk = devm_clk_get_optional(&pdev->dev, "peri_clk"); if (IS_ERR(kp->clk)) { - error = PTR_ERR(kp->clk); - if (error != -ENOENT) { - if (error != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to get clock\n"); - return error; - } - dev_dbg(&pdev->dev, - "No clock specified. Assuming it's enabled\n"); - kp->clk = NULL; + return dev_err_probe(&pdev->dev, error, "Failed to get clock\n"); + } else if (!kp->clk) { + dev_dbg(&pdev->dev, "No clock specified. Assuming it's enabled\n"); } else { unsigned int desired_rate; long actual_rate; -- GitLab From 2bdb1a9a8a1775cdf15bd1299da8fd7e9b5f10a3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:28:16 +0200 Subject: [PATCH 0034/3445] Input: bu21013_ts - use local 'client->dev' variable in probe() 'dev' is shorter and simpler than '&client->dev' and in few cases it allows to skip line wrapping. Probe function uses '&client->dev' a lot, so this improves readability slightly. Suggested-by: Andy Shevchenko Signed-off-by: Krzysztof Kozlowski Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20230625162817.100397-24-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/bu21013_ts.c | 61 ++++++++++++-------------- 1 file changed, 28 insertions(+), 33 deletions(-) diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c index f811677a59f7a..652439a79e216 100644 --- a/drivers/input/touchscreen/bu21013_ts.c +++ b/drivers/input/touchscreen/bu21013_ts.c @@ -410,31 +410,32 @@ static int bu21013_probe(struct i2c_client *client) struct input_dev *in_dev; struct input_absinfo *info; u32 max_x = 0, max_y = 0; + struct device *dev = &client->dev; int error; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_err(&client->dev, "i2c smbus byte data not supported\n"); + dev_err(dev, "i2c smbus byte data not supported\n"); return -EIO; } if (!client->irq) { - dev_err(&client->dev, "No IRQ set up\n"); + dev_err(dev, "No IRQ set up\n"); return -EINVAL; } - ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); + ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL); if (!ts) return -ENOMEM; ts->client = client; - ts->x_flip = device_property_read_bool(&client->dev, "rohm,flip-x"); - ts->y_flip = device_property_read_bool(&client->dev, "rohm,flip-y"); + ts->x_flip = device_property_read_bool(dev, "rohm,flip-x"); + ts->y_flip = device_property_read_bool(dev, "rohm,flip-y"); - in_dev = devm_input_allocate_device(&client->dev); + in_dev = devm_input_allocate_device(dev); if (!in_dev) { - dev_err(&client->dev, "device memory alloc failed\n"); + dev_err(dev, "device memory alloc failed\n"); return -ENOMEM; } ts->in_dev = in_dev; @@ -444,8 +445,8 @@ static int bu21013_probe(struct i2c_client *client) in_dev->name = DRIVER_TP; in_dev->id.bustype = BUS_I2C; - device_property_read_u32(&client->dev, "rohm,touch-max-x", &max_x); - device_property_read_u32(&client->dev, "rohm,touch-max-y", &max_y); + device_property_read_u32(dev, "rohm,touch-max-x", &max_x); + device_property_read_u32(dev, "rohm,touch-max-y", &max_y); input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0, max_x, 0, 0); input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0, max_y, 0, 0); @@ -454,14 +455,14 @@ static int bu21013_probe(struct i2c_client *client) /* Adjust for the legacy "flip" properties, if present */ if (!ts->props.invert_x && - device_property_read_bool(&client->dev, "rohm,flip-x")) { + device_property_read_bool(dev, "rohm,flip-x")) { info = &in_dev->absinfo[ABS_MT_POSITION_X]; info->maximum -= info->minimum; info->minimum = 0; } if (!ts->props.invert_y && - device_property_read_bool(&client->dev, "rohm,flip-y")) { + device_property_read_bool(dev, "rohm,flip-y")) { info = &in_dev->absinfo[ABS_MT_POSITION_Y]; info->maximum -= info->minimum; info->minimum = 0; @@ -471,50 +472,46 @@ static int bu21013_probe(struct i2c_client *client) INPUT_MT_DIRECT | INPUT_MT_TRACK | INPUT_MT_DROP_UNUSED); if (error) { - dev_err(&client->dev, "failed to initialize MT slots"); + dev_err(dev, "failed to initialize MT slots"); return error; } - ts->regulator = devm_regulator_get(&client->dev, "avdd"); + ts->regulator = devm_regulator_get(dev, "avdd"); if (IS_ERR(ts->regulator)) { - dev_err(&client->dev, "regulator_get failed\n"); + dev_err(dev, "regulator_get failed\n"); return PTR_ERR(ts->regulator); } error = regulator_enable(ts->regulator); if (error) { - dev_err(&client->dev, "regulator enable failed\n"); + dev_err(dev, "regulator enable failed\n"); return error; } - error = devm_add_action_or_reset(&client->dev, bu21013_power_off, ts); + error = devm_add_action_or_reset(dev, bu21013_power_off, ts); if (error) { - dev_err(&client->dev, "failed to install power off handler\n"); + dev_err(dev, "failed to install power off handler\n"); return error; } /* Named "CS" on the chip, DT binding is "reset" */ - ts->cs_gpiod = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); + ts->cs_gpiod = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(ts->cs_gpiod)) - return dev_err_probe(&client->dev, PTR_ERR(ts->cs_gpiod), - "failed to get CS GPIO\n"); + return dev_err_probe(dev, PTR_ERR(ts->cs_gpiod), "failed to get CS GPIO\n"); gpiod_set_consumer_name(ts->cs_gpiod, "BU21013 CS"); - error = devm_add_action_or_reset(&client->dev, - bu21013_disable_chip, ts); + error = devm_add_action_or_reset(dev, bu21013_disable_chip, ts); if (error) { - dev_err(&client->dev, - "failed to install chip disable handler\n"); + dev_err(dev, "failed to install chip disable handler\n"); return error; } /* Named "INT" on the chip, DT binding is "touch" */ - ts->int_gpiod = devm_gpiod_get_optional(&client->dev, - "touch", GPIOD_IN); + ts->int_gpiod = devm_gpiod_get_optional(dev, "touch", GPIOD_IN); error = PTR_ERR_OR_ZERO(ts->int_gpiod); if (error) - return dev_err_probe(&client->dev, error, "failed to get INT GPIO\n"); + return dev_err_probe(dev, error, "failed to get INT GPIO\n"); if (ts->int_gpiod) gpiod_set_consumer_name(ts->int_gpiod, "BU21013 INT"); @@ -522,22 +519,20 @@ static int bu21013_probe(struct i2c_client *client) /* configure the touch panel controller */ error = bu21013_init_chip(ts); if (error) { - dev_err(&client->dev, "error in bu21013 config\n"); + dev_err(dev, "error in bu21013 config\n"); return error; } - error = devm_request_threaded_irq(&client->dev, client->irq, - NULL, bu21013_gpio_irq, + error = devm_request_threaded_irq(dev, client->irq, NULL, bu21013_gpio_irq, IRQF_ONESHOT, DRIVER_TP, ts); if (error) { - dev_err(&client->dev, "request irq %d failed\n", - client->irq); + dev_err(dev, "request irq %d failed\n", client->irq); return error; } error = input_register_device(in_dev); if (error) { - dev_err(&client->dev, "failed to register input device\n"); + dev_err(dev, "failed to register input device\n"); return error; } -- GitLab From 59a51ba6e946a2a02865285eb3e10bb607033dd3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 25 Jun 2023 18:28:17 +0200 Subject: [PATCH 0035/3445] Input: bu21029_ts - use local 'client->dev' variable in probe() 'dev' is shorter and simpler than '&client->dev' and in few cases it allows to skip line wrapping. Probe function uses '&client->dev' a lot, so this improves readability slightly. Suggested-by: Andy Shevchenko Signed-off-by: Krzysztof Kozlowski Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230625162817.100397-25-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/bu21029_ts.c | 35 +++++++++++--------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/drivers/input/touchscreen/bu21029_ts.c b/drivers/input/touchscreen/bu21029_ts.c index 3d81ebe66b66c..e1dfbd92ab648 100644 --- a/drivers/input/touchscreen/bu21029_ts.c +++ b/drivers/input/touchscreen/bu21029_ts.c @@ -333,6 +333,7 @@ static void bu21029_stop_chip(struct input_dev *dev) static int bu21029_probe(struct i2c_client *client) { + struct device *dev = &client->dev; struct bu21029_ts_data *bu21029; struct input_dev *in_dev; int error; @@ -341,37 +342,33 @@ static int bu21029_probe(struct i2c_client *client) I2C_FUNC_SMBUS_WRITE_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA | I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { - dev_err(&client->dev, - "i2c functionality support is not sufficient\n"); + dev_err(dev, "i2c functionality support is not sufficient\n"); return -EIO; } - bu21029 = devm_kzalloc(&client->dev, sizeof(*bu21029), GFP_KERNEL); + bu21029 = devm_kzalloc(dev, sizeof(*bu21029), GFP_KERNEL); if (!bu21029) return -ENOMEM; - error = device_property_read_u32(&client->dev, "rohm,x-plate-ohms", - &bu21029->x_plate_ohms); + error = device_property_read_u32(dev, "rohm,x-plate-ohms", &bu21029->x_plate_ohms); if (error) { - dev_err(&client->dev, - "invalid 'x-plate-ohms' supplied: %d\n", error); + dev_err(dev, "invalid 'x-plate-ohms' supplied: %d\n", error); return error; } - bu21029->vdd = devm_regulator_get(&client->dev, "vdd"); + bu21029->vdd = devm_regulator_get(dev, "vdd"); if (IS_ERR(bu21029->vdd)) - return dev_err_probe(&client->dev, PTR_ERR(bu21029->vdd), + return dev_err_probe(dev, PTR_ERR(bu21029->vdd), "failed to acquire 'vdd' supply\n"); - bu21029->reset_gpios = devm_gpiod_get_optional(&client->dev, - "reset", GPIOD_OUT_HIGH); + bu21029->reset_gpios = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(bu21029->reset_gpios)) - return dev_err_probe(&client->dev, PTR_ERR(bu21029->reset_gpios), + return dev_err_probe(dev, PTR_ERR(bu21029->reset_gpios), "failed to acquire 'reset' gpio\n"); - in_dev = devm_input_allocate_device(&client->dev); + in_dev = devm_input_allocate_device(dev); if (!in_dev) { - dev_err(&client->dev, "unable to allocate input device\n"); + dev_err(dev, "unable to allocate input device\n"); return -ENOMEM; } @@ -392,20 +389,18 @@ static int bu21029_probe(struct i2c_client *client) input_set_drvdata(in_dev, bu21029); - error = devm_request_threaded_irq(&client->dev, client->irq, - NULL, bu21029_touch_soft_irq, + error = devm_request_threaded_irq(dev, client->irq, NULL, + bu21029_touch_soft_irq, IRQF_ONESHOT | IRQF_NO_AUTOEN, DRIVER_NAME, bu21029); if (error) { - dev_err(&client->dev, - "unable to request touch irq: %d\n", error); + dev_err(dev, "unable to request touch irq: %d\n", error); return error; } error = input_register_device(in_dev); if (error) { - dev_err(&client->dev, - "unable to register input device: %d\n", error); + dev_err(dev, "unable to register input device: %d\n", error); return error; } -- GitLab From 3ce6e06202b49802e8e0c4c8858717f534a308d0 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 17 Jun 2023 09:05:42 +0200 Subject: [PATCH 0036/3445] Input: pinephone-keyboard - use devm_regulator_get_enable() Use devm_regulator_get_enable() instead of hand writing it. It saves some line of code. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/78d7a4719ed7c372a7aa62afb66d4f1561799b5f.1686985515.git.christophe.jaillet@wanadoo.fr Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/pinephone-keyboard.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/drivers/input/keyboard/pinephone-keyboard.c b/drivers/input/keyboard/pinephone-keyboard.c index 038ff3549a7ac..147b1f288a334 100644 --- a/drivers/input/keyboard/pinephone-keyboard.c +++ b/drivers/input/keyboard/pinephone-keyboard.c @@ -318,40 +318,22 @@ static void ppkb_close(struct input_dev *input) ppkb_set_scan(client, false); } -static void ppkb_regulator_disable(void *regulator) -{ - regulator_disable(regulator); -} - static int ppkb_probe(struct i2c_client *client) { struct device *dev = &client->dev; unsigned int phys_rows, phys_cols; struct pinephone_keyboard *ppkb; - struct regulator *vbat_supply; u8 info[PPKB_MATRIX_SIZE + 1]; struct device_node *i2c_bus; int ret; int error; - vbat_supply = devm_regulator_get(dev, "vbat"); - error = PTR_ERR_OR_ZERO(vbat_supply); + error = devm_regulator_get_enable(dev, "vbat"); if (error) { dev_err(dev, "Failed to get VBAT supply: %d\n", error); return error; } - error = regulator_enable(vbat_supply); - if (error) { - dev_err(dev, "Failed to enable VBAT: %d\n", error); - return error; - } - - error = devm_add_action_or_reset(dev, ppkb_regulator_disable, - vbat_supply); - if (error) - return error; - ret = i2c_smbus_read_i2c_block_data(client, 0, sizeof(info), info); if (ret != sizeof(info)) { error = ret < 0 ? ret : -EIO; -- GitLab From 26ab82616eb51bd236f12d6427d05d18c573f6e2 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 17 Jun 2023 09:12:03 +0200 Subject: [PATCH 0037/3445] Input: adp5588-keys - use devm_regulator_get_enable() Use devm_regulator_get_enable() instead of hand writing it. It saves some line of code. Signed-off-by: Christophe JAILLET Acked-by: Michael Hennerich Link: https://lore.kernel.org/r/af343b5b0d740cc9f8863264c30e3da4215721d7.1686985911.git.christophe.jaillet@wanadoo.fr Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/adp5588-keys.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index 896a5a989ddce..61e8e43e9c2bb 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -713,17 +713,11 @@ static int adp5588_fw_parse(struct adp5588_kpad *kpad) return 0; } -static void adp5588_disable_regulator(void *reg) -{ - regulator_disable(reg); -} - static int adp5588_probe(struct i2c_client *client) { struct adp5588_kpad *kpad; struct input_dev *input; struct gpio_desc *gpio; - struct regulator *vcc; unsigned int revid; int ret; int error; @@ -749,16 +743,7 @@ static int adp5588_probe(struct i2c_client *client) if (error) return error; - vcc = devm_regulator_get(&client->dev, "vcc"); - if (IS_ERR(vcc)) - return PTR_ERR(vcc); - - error = regulator_enable(vcc); - if (error) - return error; - - error = devm_add_action_or_reset(&client->dev, - adp5588_disable_regulator, vcc); + error = devm_regulator_get_enable(&client->dev, "vcc"); if (error) return error; -- GitLab From 685b37704ce68924fa823d1cc37e512555526e06 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 21 Jun 2023 11:32:45 +0200 Subject: [PATCH 0038/3445] dt-bindings: input: touchscreen: edt-ft5x06: Add 'threshold' property Add a new property 'threshold' to the edt-ft5x06 touchscreen binding. This property allows setting the "click"-threshold in the range from 0 to 255. This change addresses the following dtbs_check warning: imx6dl-lanmcu.dtb: touchscreen@38: 'threshold' does not match any of the regexes: 'pinctrl-[0-9]+' Signed-off-by: Oleksij Rempel Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230621093245.78130-6-o.rempel@pengutronix.de Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/touchscreen/edt-ft5x06.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.yaml b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.yaml index ef4c841387bdd..f2808cb4d99df 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.yaml @@ -93,6 +93,12 @@ properties: minimum: 1 maximum: 255 + threshold: + description: Allows setting the "click"-threshold in the range from 0 to 255. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + touchscreen-size-x: true touchscreen-size-y: true touchscreen-fuzz-x: true -- GitLab From 85429376884f239f854e9b5c6d9defaa1de4619e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 10 Jul 2023 14:36:32 +0200 Subject: [PATCH 0039/3445] Input: novatek-nvt-ts - fix input_register_device() failure error message Fix input_register_device() failure logging "failed to request irq" as error message. Reviewed-by: Peter Hutterer Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20230710123633.323937-1-hdegoede@redhat.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/novatek-nvt-ts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/novatek-nvt-ts.c b/drivers/input/touchscreen/novatek-nvt-ts.c index 7f7d879aac6d5..047e371448cef 100644 --- a/drivers/input/touchscreen/novatek-nvt-ts.c +++ b/drivers/input/touchscreen/novatek-nvt-ts.c @@ -272,7 +272,7 @@ static int nvt_ts_probe(struct i2c_client *client) error = input_register_device(input); if (error) { - dev_err(dev, "failed to request irq: %d\n", error); + dev_err(dev, "failed to register input device: %d\n", error); return error; } -- GitLab From 7249bdbd5eae873557abcee25f30a8b0d2fc4b3f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 10 Jul 2023 14:36:33 +0200 Subject: [PATCH 0040/3445] Input: novatek-nvt-ts - add touchscreen model number to description A phoronix forum member actual found documentation on what the model number for the touchscreen controller on the Acer Iconia One 7 B1-750 is. Update the driver's description to include this. Link: https://www.phoronix.com/forums/forum/hardware/general-hardware/1382535-10-years-later-linux-getting-a-touchscreen-driver-for-a-once-popular-tablet?p=1384707#post1384707 Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20230710123633.323937-2-hdegoede@redhat.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 4 ++-- drivers/input/touchscreen/novatek-nvt-ts.c | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index c2cbd332af1df..fb4c23917b69d 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -655,10 +655,10 @@ config TOUCHSCREEN_MTOUCH module will be called mtouch. config TOUCHSCREEN_NOVATEK_NVT_TS - tristate "Novatek NVT-ts touchscreen support" + tristate "Novatek NT11205 touchscreen support" depends on I2C help - Say Y here if you have a Novatek NVT-ts touchscreen. + Say Y here if you have a Novatek NT11205 touchscreen. If unsure, say N. To compile this driver as a module, choose M here: the diff --git a/drivers/input/touchscreen/novatek-nvt-ts.c b/drivers/input/touchscreen/novatek-nvt-ts.c index 047e371448cef..1a797e410a3fa 100644 --- a/drivers/input/touchscreen/novatek-nvt-ts.c +++ b/drivers/input/touchscreen/novatek-nvt-ts.c @@ -1,9 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Driver for Novatek i2c touchscreen controller as found on - * the Acer Iconia One 7 B1-750 tablet. The Touchscreen controller - * model-number is unknown. Android calls this a "NVT-ts" touchscreen, - * but that may apply to other Novatek controller models too. + * Driver for Novatek NT11205 i2c touchscreen controller as found + * on the Acer Iconia One 7 B1-750 tablet. * * Copyright (c) 2023 Hans de Goede */ @@ -296,6 +294,6 @@ static struct i2c_driver nvt_ts_driver = { module_i2c_driver(nvt_ts_driver); -MODULE_DESCRIPTION("Novatek NVT-ts touchscreen driver"); +MODULE_DESCRIPTION("Novatek NT11205 touchscreen driver"); MODULE_AUTHOR("Hans de Goede "); MODULE_LICENSE("GPL"); -- GitLab From 80c268c3394e9a7118c4ce0fee0eaffab85b762a Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sun, 9 Jul 2023 15:41:08 +0200 Subject: [PATCH 0041/3445] Input: tegra-kbc - use devm_platform_ioremap_resource devm_platform_get_and_ioremap_resource maps a resource and returns its physical address. If we don't need the physical address, we should call devm_platform_ioremap_resource instead. Signed-off-by: Martin Kaiser Acked-by: Thierry Reding Link: https://lore.kernel.org/r/20230709134109.182418-1-martin@kaiser.cx Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tegra-kbc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index d5a6c7d8eb25d..c9a823ea45d02 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -640,7 +640,7 @@ static int tegra_kbc_probe(struct platform_device *pdev) timer_setup(&kbc->timer, tegra_kbc_keypress_timer, 0); - kbc->mmio = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + kbc->mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(kbc->mmio)) return PTR_ERR(kbc->mmio); -- GitLab From 2e00b8bf5624767f6be7427b6eb532524793463e Mon Sep 17 00:00:00 2001 From: Jeff LaBundy Date: Sun, 9 Jul 2023 12:06:37 -0500 Subject: [PATCH 0042/3445] Input: iqs7222 - configure power mode before triggering ATI If the device drops into ultra-low-power mode before being placed into normal-power mode as part of ATI being triggered, the device does not assert any interrupts until the ATI routine is restarted two seconds later. Solve this problem by adopting the vendor's recommendation, which calls for the device to be placed into normal-power mode prior to being configured and ATI being triggered. The original implementation followed this sequence, but the order was inadvertently changed as part of the resolution of a separate erratum. Fixes: 1e4189d8af27 ("Input: iqs7222 - protect volatile registers") Signed-off-by: Jeff LaBundy Link: https://lore.kernel.org/r/ZKrpHc2Ji9qR25r2@nixie71 Signed-off-by: Dmitry Torokhov --- drivers/input/misc/iqs7222.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/input/misc/iqs7222.c b/drivers/input/misc/iqs7222.c index 096b0925f41ba..acb95048e8230 100644 --- a/drivers/input/misc/iqs7222.c +++ b/drivers/input/misc/iqs7222.c @@ -1381,9 +1381,6 @@ static int iqs7222_ati_trigger(struct iqs7222_private *iqs7222) if (error) return error; - sys_setup &= ~IQS7222_SYS_SETUP_INTF_MODE_MASK; - sys_setup &= ~IQS7222_SYS_SETUP_PWR_MODE_MASK; - for (i = 0; i < IQS7222_NUM_RETRIES; i++) { /* * Trigger ATI from streaming and normal-power modes so that @@ -1561,8 +1558,11 @@ static int iqs7222_dev_init(struct iqs7222_private *iqs7222, int dir) return error; } - if (dir == READ) + if (dir == READ) { + iqs7222->sys_setup[0] &= ~IQS7222_SYS_SETUP_INTF_MODE_MASK; + iqs7222->sys_setup[0] &= ~IQS7222_SYS_SETUP_PWR_MODE_MASK; return 0; + } return iqs7222_ati_trigger(iqs7222); } -- GitLab From 92b46a7bd1c4966e8178da008930cdc0af43dad8 Mon Sep 17 00:00:00 2001 From: Jeff LaBundy Date: Sun, 9 Jul 2023 12:06:57 -0500 Subject: [PATCH 0043/3445] dt-bindings: input: iqs7222: Define units for slider properties The units assumed by the 'azoteq,top-speed', 'azoteq,bottom-speed' and 'azoteq,gesture-dist' properties are unspecified; define them according to the device's datasheet. Signed-off-by: Jeff LaBundy Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/ZKrpMekZBt95Gmnr@nixie71 Signed-off-by: Dmitry Torokhov --- .../bindings/input/azoteq,iqs7222.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/input/azoteq,iqs7222.yaml b/Documentation/devicetree/bindings/input/azoteq,iqs7222.yaml index 9ddba7f2e7aa6..4c8690b62ce00 100644 --- a/Documentation/devicetree/bindings/input/azoteq,iqs7222.yaml +++ b/Documentation/devicetree/bindings/input/azoteq,iqs7222.yaml @@ -521,16 +521,16 @@ patternProperties: minimum: 0 maximum: 65535 description: - Specifies the speed of movement after which coordinate filtering is - no longer applied. + Specifies the speed (in coordinates traveled per conversion) after + which coordinate filtering is no longer applied. azoteq,bottom-speed: $ref: /schemas/types.yaml#/definitions/uint32 minimum: 0 maximum: 255 description: - Specifies the speed of movement after which coordinate filtering is - linearly reduced. + Specifies the speed (in coordinates traveled per conversion) after + which coordinate filtering is linearly reduced. azoteq,bottom-beta: $ref: /schemas/types.yaml#/definitions/uint32 @@ -595,10 +595,10 @@ patternProperties: minimum: 0 maximum: 4080 description: - Specifies the distance across which a swipe or flick gesture must - travel in order to be acknowledged by the device. The number spec- - ified for any one swipe or flick gesture applies to all remaining - swipe or flick gestures. + Specifies the distance (in coordinates) across which a swipe or + flick gesture must travel in order to be acknowledged by the + device. The number specified for any one swipe or flick gesture + applies to all remaining swipe or flick gestures. azoteq,gpio-select: $ref: /schemas/types.yaml#/definitions/uint32-array -- GitLab From 823b28c5e590cccbfc94e69f06a884278dde7943 Mon Sep 17 00:00:00 2001 From: Jeff LaBundy Date: Sun, 9 Jul 2023 12:07:05 -0500 Subject: [PATCH 0044/3445] dt-bindings: input: iqs7222: Add properties for Azoteq IQS7222D Extend the common binding to include a new variant of the silicon, which effectively replaces a pair of slider nodes with a trackpad node comprising the same or similar properties. As part of this change, the if/then/else schema have been updated to identify properties that are not supported by the new device. Signed-off-by: Jeff LaBundy Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/ZKrpOdp+rM8gDekw@nixie71 Signed-off-by: Dmitry Torokhov --- .../bindings/input/azoteq,iqs7222.yaml | 232 ++++++++++++++++-- 1 file changed, 215 insertions(+), 17 deletions(-) diff --git a/Documentation/devicetree/bindings/input/azoteq,iqs7222.yaml b/Documentation/devicetree/bindings/input/azoteq,iqs7222.yaml index 4c8690b62ce00..5b1769c19b173 100644 --- a/Documentation/devicetree/bindings/input/azoteq,iqs7222.yaml +++ b/Documentation/devicetree/bindings/input/azoteq,iqs7222.yaml @@ -4,14 +4,14 @@ $id: http://devicetree.org/schemas/input/azoteq,iqs7222.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Azoteq IQS7222A/B/C Capacitive Touch Controller +title: Azoteq IQS7222A/B/C/D Capacitive Touch Controller maintainers: - Jeff LaBundy description: | - The Azoteq IQS7222A, IQS7222B and IQS7222C are multichannel capacitive touch - controllers that feature additional sensing capabilities. + The Azoteq IQS7222A, IQS7222B, IQS7222C and IQS7222D are multichannel + capacitive touch controllers that feature additional sensing capabilities. Link to datasheets: https://www.azoteq.com/ @@ -21,6 +21,7 @@ properties: - azoteq,iqs7222a - azoteq,iqs7222b - azoteq,iqs7222c + - azoteq,iqs7222d reg: maxItems: 1 @@ -173,6 +174,152 @@ properties: maximum: 3000 description: Specifies the report rate (in ms) during ultra-low-power mode. + touchscreen-size-x: true + touchscreen-size-y: true + touchscreen-inverted-x: true + touchscreen-inverted-y: true + touchscreen-swapped-x-y: true + + trackpad: + type: object + description: Represents all channels associated with the trackpad. + + properties: + azoteq,channel-select: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 12 + items: + minimum: 0 + maximum: 13 + description: + Specifies the order of the channels that participate in the trackpad. + Specify 255 to omit a given channel for the purpose of mapping a non- + rectangular trackpad. + + azoteq,num-rows: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + maximum: 12 + description: Specifies the number of rows that comprise the trackpad. + + azoteq,num-cols: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + maximum: 12 + description: Specifies the number of columns that comprise the trackpad. + + azoteq,top-speed: + $ref: /schemas/types.yaml#/definitions/uint32 + multipleOf: 4 + minimum: 0 + maximum: 1020 + description: + Specifies the speed (in coordinates traveled per conversion) after + which coordinate filtering is no longer applied. + + azoteq,bottom-speed: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + description: + Specifies the speed (in coordinates traveled per conversion) after + which coordinate filtering is linearly reduced. + + azoteq,use-prox: + type: boolean + description: + Directs the trackpad to respond to the proximity states of the + selected channels instead of their corresponding touch states. + Note the trackpad cannot report granular coordinates during a + state of proximity. + + patternProperties: + "^azoteq,lower-cal-(x|y)$": + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + description: Specifies the trackpad's lower starting points. + + "^azoteq,upper-cal-(x|y)$": + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + description: Specifies the trackpad's upper starting points. + + "^event-(press|tap|(swipe|flick)-(x|y)-(pos|neg))$": + type: object + $ref: input.yaml# + description: + Represents a press or gesture event reported by the trackpad. Specify + 'linux,code' under the press event to report absolute coordinates. + + properties: + linux,code: true + + azoteq,gesture-angle-tighten: + type: boolean + description: + Limits the tangent of the gesture angle to 0.5 (axial gestures + only). If specified in one direction, the effect is applied in + either direction. + + azoteq,gesture-max-ms: + multipleOf: 16 + minimum: 0 + maximum: 4080 + description: + Specifies the length of time (in ms) within which a tap, swipe + or flick gesture must be completed in order to be acknowledged + by the device. The number specified for any one swipe or flick + gesture applies to all other swipe or flick gestures. + + azoteq,gesture-min-ms: + multipleOf: 16 + minimum: 0 + maximum: 4080 + description: + Specifies the length of time (in ms) for which a tap gesture must + be held in order to be acknowledged by the device. + + azoteq,gesture-dist: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 65535 + description: + Specifies the distance (in coordinates) across which a swipe or + flick gesture must travel in order to be acknowledged by the + device. The number specified for any one swipe or flick gesture + applies to all remaining swipe or flick gestures. + + For tap gestures, this property specifies the distance from the + original point of contact across which the contact is permitted + to travel before the gesture is rejected by the device. + + azoteq,gpio-select: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 3 + items: + minimum: 0 + maximum: 2 + description: | + Specifies one or more GPIO mapped to the event as follows: + 0: GPIO0 + 1: GPIO3 + 2: GPIO4 + + Note that although multiple events can be mapped to a single + GPIO, they must all be of the same type (proximity, touch or + trackpad gesture). + + additionalProperties: false + + required: + - azoteq,channel-select + + additionalProperties: false + patternProperties: "^cycle-[0-9]$": type: object @@ -288,6 +435,10 @@ patternProperties: Activates the reference channel in response to proximity events instead of touch events. + azoteq,counts-filt-enable: + type: boolean + description: Applies counts filtering to the channel. + azoteq,ati-band: $ref: /schemas/types.yaml#/definitions/uint32 enum: [0, 1, 2, 3] @@ -432,12 +583,12 @@ patternProperties: description: | Specifies one or more GPIO mapped to the event as follows: 0: GPIO0 - 1: GPIO3 (IQS7222C only) - 2: GPIO4 (IQS7222C only) + 1: GPIO3 + 2: GPIO4 Note that although multiple events can be mapped to a single GPIO, they must all be of the same type (proximity, touch or - slider gesture). + slider/trackpad gesture). azoteq,thresh: $ref: /schemas/types.yaml#/definitions/uint32 @@ -610,8 +761,8 @@ patternProperties: description: | Specifies one or more GPIO mapped to the event as follows: 0: GPIO0 - 1: GPIO3 (IQS7222C only) - 2: GPIO4 (IQS7222C only) + 1: GPIO3 + 2: GPIO4 Note that although multiple events can be mapped to a single GPIO, they must all be of the same type (proximity, touch or @@ -629,8 +780,8 @@ patternProperties: description: | Represents a GPIO mapped to one or more events as follows: gpio-0: GPIO0 - gpio-1: GPIO3 (IQS7222C only) - gpio-2: GPIO4 (IQS7222C only) + gpio-1: GPIO3 + gpio-2: GPIO4 allOf: - $ref: ../pinctrl/pincfg-node.yaml# @@ -641,11 +792,53 @@ patternProperties: additionalProperties: false allOf: + - $ref: touchscreen/touchscreen.yaml# + - if: properties: compatible: contains: - const: azoteq,iqs7222b + enum: + - azoteq,iqs7222a + - azoteq,iqs7222b + - azoteq,iqs7222c + + then: + properties: + touchscreen-size-x: false + touchscreen-size-y: false + touchscreen-inverted-x: false + touchscreen-inverted-y: false + touchscreen-swapped-x-y: false + + trackpad: false + + patternProperties: + "^channel-([0-9]|1[0-9])$": + properties: + azoteq,counts-filt-enable: false + + - if: + properties: + compatible: + contains: + enum: + - azoteq,iqs7222b + - azoteq,iqs7222c + + then: + patternProperties: + "^channel-([0-9]|1[0-9])$": + properties: + azoteq,ulp-allow: false + + - if: + properties: + compatible: + contains: + enum: + - azoteq,iqs7222b + - azoteq,iqs7222d then: patternProperties: @@ -657,13 +850,22 @@ allOf: properties: azoteq,ref-select: false + "^slider-[0-1]$": false + + - if: + properties: + compatible: + contains: + const: azoteq,iqs7222b + + then: + patternProperties: + "^channel-([0-9]|1[0-9])$": patternProperties: "^event-(prox|touch)$": properties: azoteq,gpio-select: false - "^slider-[0-1]$": false - "^gpio-[0-2]$": false - if: @@ -704,10 +906,6 @@ allOf: else: patternProperties: - "^channel-([0-9]|1[0-9])$": - properties: - azoteq,ulp-allow: false - "^slider-[0-1]$": patternProperties: "^event-(press|tap|(swipe|flick)-(pos|neg))$": -- GitLab From dd24e202ac722b3fea1fadb7f6c0b2db61086e78 Mon Sep 17 00:00:00 2001 From: Jeff LaBundy Date: Sun, 9 Jul 2023 12:07:18 -0500 Subject: [PATCH 0045/3445] Input: iqs7222 - add support for Azoteq IQS7222D The vendor has introduced a new variant of silicon which is highly similar to the existing IQS7222A, but with its independent sliders essentially replaced with a single-contact trackpad. Update the common driver to support this new device's register map and report trackpad events. As with the IQS7222A, the new IQS7222D can report both raw coordinates as well as gestures. Signed-off-by: Jeff LaBundy Link: https://lore.kernel.org/r/ZKrpRh6RT6+6KrMQ@nixie71 Signed-off-by: Dmitry Torokhov --- drivers/input/misc/Kconfig | 4 +- drivers/input/misc/iqs7222.c | 468 ++++++++++++++++++++++++++++++++++- 2 files changed, 461 insertions(+), 11 deletions(-) diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 81a54a59e13c4..c47eecc6f83bb 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -791,10 +791,10 @@ config INPUT_IQS626A module will be called iqs626a. config INPUT_IQS7222 - tristate "Azoteq IQS7222A/B/C capacitive touch controller" + tristate "Azoteq IQS7222A/B/C/D capacitive touch controller" depends on I2C help - Say Y to enable support for the Azoteq IQS7222A/B/C family + Say Y to enable support for the Azoteq IQS7222A/B/C/D family of capacitive touch controllers. To compile this driver as a module, choose M here: the diff --git a/drivers/input/misc/iqs7222.c b/drivers/input/misc/iqs7222.c index acb95048e8230..a9c1dba1e8c1d 100644 --- a/drivers/input/misc/iqs7222.c +++ b/drivers/input/misc/iqs7222.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Azoteq IQS7222A/B/C Capacitive Touch Controller + * Azoteq IQS7222A/B/C/D Capacitive Touch Controller * * Copyright (C) 2022 Jeff LaBundy */ @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,7 @@ #define IQS7222_PROD_NUM_A 840 #define IQS7222_PROD_NUM_B 698 #define IQS7222_PROD_NUM_C 863 +#define IQS7222_PROD_NUM_D 1046 #define IQS7222_SYS_STATUS 0x10 #define IQS7222_SYS_STATUS_RESET BIT(3) @@ -54,6 +56,7 @@ #define IQS7222_EVENT_MASK_ATI BIT(12) #define IQS7222_EVENT_MASK_SLDR BIT(10) +#define IQS7222_EVENT_MASK_TPAD IQS7222_EVENT_MASK_SLDR #define IQS7222_EVENT_MASK_TOUCH BIT(1) #define IQS7222_EVENT_MASK_PROX BIT(0) @@ -71,6 +74,7 @@ #define IQS7222_MAX_COLS_CHAN 6 #define IQS7222_MAX_COLS_FILT 2 #define IQS7222_MAX_COLS_SLDR 11 +#define IQS7222_MAX_COLS_TPAD 24 #define IQS7222_MAX_COLS_GPIO 3 #define IQS7222_MAX_COLS_SYS 13 @@ -102,16 +106,18 @@ enum iqs7222_reg_grp_id { IQS7222_REG_GRP_BTN, IQS7222_REG_GRP_CHAN, IQS7222_REG_GRP_SLDR, + IQS7222_REG_GRP_TPAD, IQS7222_REG_GRP_GPIO, IQS7222_REG_GRP_SYS, IQS7222_NUM_REG_GRPS }; static const char * const iqs7222_reg_grp_names[IQS7222_NUM_REG_GRPS] = { - [IQS7222_REG_GRP_CYCLE] = "cycle", - [IQS7222_REG_GRP_CHAN] = "channel", - [IQS7222_REG_GRP_SLDR] = "slider", - [IQS7222_REG_GRP_GPIO] = "gpio", + [IQS7222_REG_GRP_CYCLE] = "cycle-%d", + [IQS7222_REG_GRP_CHAN] = "channel-%d", + [IQS7222_REG_GRP_SLDR] = "slider-%d", + [IQS7222_REG_GRP_TPAD] = "trackpad", + [IQS7222_REG_GRP_GPIO] = "gpio-%d", }; static const unsigned int iqs7222_max_cols[IQS7222_NUM_REG_GRPS] = { @@ -122,6 +128,7 @@ static const unsigned int iqs7222_max_cols[IQS7222_NUM_REG_GRPS] = { [IQS7222_REG_GRP_CHAN] = IQS7222_MAX_COLS_CHAN, [IQS7222_REG_GRP_FILT] = IQS7222_MAX_COLS_FILT, [IQS7222_REG_GRP_SLDR] = IQS7222_MAX_COLS_SLDR, + [IQS7222_REG_GRP_TPAD] = IQS7222_MAX_COLS_TPAD, [IQS7222_REG_GRP_GPIO] = IQS7222_MAX_COLS_GPIO, [IQS7222_REG_GRP_SYS] = IQS7222_MAX_COLS_SYS, }; @@ -130,8 +137,10 @@ static const unsigned int iqs7222_gpio_links[] = { 2, 5, 6, }; struct iqs7222_event_desc { const char *name; + u16 link; u16 mask; u16 val; + u16 strict; u16 enable; enum iqs7222_reg_key_id reg_key; }; @@ -188,6 +197,93 @@ static const struct iqs7222_event_desc iqs7222_sl_events[] = { }, }; +static const struct iqs7222_event_desc iqs7222_tp_events[] = { + { + .name = "event-press", + .link = BIT(7), + }, + { + .name = "event-tap", + .link = BIT(0), + .mask = BIT(0), + .val = BIT(0), + .enable = BIT(0), + .reg_key = IQS7222_REG_KEY_TAP, + }, + { + .name = "event-swipe-x-pos", + .link = BIT(2), + .mask = BIT(2) | BIT(1), + .val = BIT(2), + .strict = BIT(4), + .enable = BIT(1), + .reg_key = IQS7222_REG_KEY_AXIAL, + }, + { + .name = "event-swipe-y-pos", + .link = BIT(3), + .mask = BIT(3) | BIT(1), + .val = BIT(3), + .strict = BIT(3), + .enable = BIT(1), + .reg_key = IQS7222_REG_KEY_AXIAL, + }, + { + .name = "event-swipe-x-neg", + .link = BIT(4), + .mask = BIT(4) | BIT(1), + .val = BIT(4), + .strict = BIT(4), + .enable = BIT(1), + .reg_key = IQS7222_REG_KEY_AXIAL, + }, + { + .name = "event-swipe-y-neg", + .link = BIT(5), + .mask = BIT(5) | BIT(1), + .val = BIT(5), + .strict = BIT(3), + .enable = BIT(1), + .reg_key = IQS7222_REG_KEY_AXIAL, + }, + { + .name = "event-flick-x-pos", + .link = BIT(2), + .mask = BIT(2) | BIT(1), + .val = BIT(2) | BIT(1), + .strict = BIT(4), + .enable = BIT(2), + .reg_key = IQS7222_REG_KEY_AXIAL, + }, + { + .name = "event-flick-y-pos", + .link = BIT(3), + .mask = BIT(3) | BIT(1), + .val = BIT(3) | BIT(1), + .strict = BIT(3), + .enable = BIT(2), + .reg_key = IQS7222_REG_KEY_AXIAL, + }, + { + .name = "event-flick-x-neg", + .link = BIT(4), + .mask = BIT(4) | BIT(1), + .val = BIT(4) | BIT(1), + .strict = BIT(4), + .enable = BIT(2), + .reg_key = IQS7222_REG_KEY_AXIAL, + }, + { + .name = "event-flick-y-neg", + .link = BIT(5), + .mask = BIT(5) | BIT(1), + .val = BIT(5) | BIT(1), + .strict = BIT(3), + .enable = BIT(2), + .reg_key = IQS7222_REG_KEY_AXIAL, + }, +}; + struct iqs7222_reg_grp_desc { u16 base; int num_row; @@ -524,6 +620,62 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = { }, }, }, + { + .prod_num = IQS7222_PROD_NUM_D, + .fw_major = 0, + .fw_minor = 37, + .touch_link = 1770, + .allow_offset = 9, + .event_offset = 10, + .comms_offset = 11, + .reg_grps = { + [IQS7222_REG_GRP_STAT] = { + .base = IQS7222_SYS_STATUS, + .num_row = 1, + .num_col = 7, + }, + [IQS7222_REG_GRP_CYCLE] = { + .base = 0x8000, + .num_row = 7, + .num_col = 2, + }, + [IQS7222_REG_GRP_GLBL] = { + .base = 0x8700, + .num_row = 1, + .num_col = 3, + }, + [IQS7222_REG_GRP_BTN] = { + .base = 0x9000, + .num_row = 14, + .num_col = 3, + }, + [IQS7222_REG_GRP_CHAN] = { + .base = 0xA000, + .num_row = 14, + .num_col = 4, + }, + [IQS7222_REG_GRP_FILT] = { + .base = 0xAE00, + .num_row = 1, + .num_col = 2, + }, + [IQS7222_REG_GRP_TPAD] = { + .base = 0xB000, + .num_row = 1, + .num_col = 24, + }, + [IQS7222_REG_GRP_GPIO] = { + .base = 0xC000, + .num_row = 3, + .num_col = 3, + }, + [IQS7222_REG_GRP_SYS] = { + .base = IQS7222_SYS_SETUP, + .num_row = 1, + .num_col = 12, + }, + }, + }, }; struct iqs7222_prop_desc { @@ -1008,6 +1160,123 @@ static const struct iqs7222_prop_desc iqs7222_props[] = { .val_pitch = 4, .label = "maximum gesture time", }, + { + .name = "azoteq,num-rows", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_offset = 0, + .reg_shift = 4, + .reg_width = 4, + .val_min = 1, + .val_max = 12, + .label = "number of rows", + }, + { + .name = "azoteq,num-cols", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_offset = 0, + .reg_shift = 0, + .reg_width = 4, + .val_min = 1, + .val_max = 12, + .label = "number of columns", + }, + { + .name = "azoteq,lower-cal-y", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_offset = 1, + .reg_shift = 8, + .reg_width = 8, + .label = "lower vertical calibration", + }, + { + .name = "azoteq,lower-cal-x", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_offset = 1, + .reg_shift = 0, + .reg_width = 8, + .label = "lower horizontal calibration", + }, + { + .name = "azoteq,upper-cal-y", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_offset = 2, + .reg_shift = 8, + .reg_width = 8, + .label = "upper vertical calibration", + }, + { + .name = "azoteq,upper-cal-x", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_offset = 2, + .reg_shift = 0, + .reg_width = 8, + .label = "upper horizontal calibration", + }, + { + .name = "azoteq,top-speed", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_offset = 3, + .reg_shift = 8, + .reg_width = 8, + .val_pitch = 4, + .label = "top speed", + }, + { + .name = "azoteq,bottom-speed", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_offset = 3, + .reg_shift = 0, + .reg_width = 8, + .label = "bottom speed", + }, + { + .name = "azoteq,gesture-min-ms", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_key = IQS7222_REG_KEY_TAP, + .reg_offset = 20, + .reg_shift = 8, + .reg_width = 8, + .val_pitch = 16, + .label = "minimum gesture time", + }, + { + .name = "azoteq,gesture-max-ms", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_key = IQS7222_REG_KEY_AXIAL, + .reg_offset = 21, + .reg_shift = 8, + .reg_width = 8, + .val_pitch = 16, + .label = "maximum gesture time", + }, + { + .name = "azoteq,gesture-max-ms", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_key = IQS7222_REG_KEY_TAP, + .reg_offset = 21, + .reg_shift = 0, + .reg_width = 8, + .val_pitch = 16, + .label = "maximum gesture time", + }, + { + .name = "azoteq,gesture-dist", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_key = IQS7222_REG_KEY_TAP, + .reg_offset = 22, + .reg_shift = 0, + .reg_width = 16, + .label = "gesture distance", + }, + { + .name = "azoteq,gesture-dist", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_key = IQS7222_REG_KEY_AXIAL, + .reg_offset = 23, + .reg_shift = 0, + .reg_width = 16, + .label = "gesture distance", + }, { .name = "drive-open-drain", .reg_grp = IQS7222_REG_GRP_GPIO, @@ -1091,16 +1360,19 @@ struct iqs7222_private { struct gpio_desc *irq_gpio; struct i2c_client *client; struct input_dev *keypad; + struct touchscreen_properties prop; unsigned int kp_type[IQS7222_MAX_CHAN][ARRAY_SIZE(iqs7222_kp_events)]; unsigned int kp_code[IQS7222_MAX_CHAN][ARRAY_SIZE(iqs7222_kp_events)]; unsigned int sl_code[IQS7222_MAX_SLDR][ARRAY_SIZE(iqs7222_sl_events)]; unsigned int sl_axis[IQS7222_MAX_SLDR]; + unsigned int tp_code[ARRAY_SIZE(iqs7222_tp_events)]; u16 cycle_setup[IQS7222_MAX_CHAN / 2][IQS7222_MAX_COLS_CYCLE]; u16 glbl_setup[IQS7222_MAX_COLS_GLBL]; u16 btn_setup[IQS7222_MAX_CHAN][IQS7222_MAX_COLS_BTN]; u16 chan_setup[IQS7222_MAX_CHAN][IQS7222_MAX_COLS_CHAN]; u16 filt_setup[IQS7222_MAX_COLS_FILT]; u16 sldr_setup[IQS7222_MAX_SLDR][IQS7222_MAX_COLS_SLDR]; + u16 tpad_setup[IQS7222_MAX_COLS_TPAD]; u16 gpio_setup[ARRAY_SIZE(iqs7222_gpio_links)][IQS7222_MAX_COLS_GPIO]; u16 sys_setup[IQS7222_MAX_COLS_SYS]; }; @@ -1127,6 +1399,9 @@ static u16 *iqs7222_setup(struct iqs7222_private *iqs7222, case IQS7222_REG_GRP_SLDR: return iqs7222->sldr_setup[row]; + case IQS7222_REG_GRP_TPAD: + return iqs7222->tpad_setup; + case IQS7222_REG_GRP_GPIO: return iqs7222->gpio_setup[row]; @@ -1936,6 +2211,14 @@ static int iqs7222_parse_chan(struct iqs7222_private *iqs7222, ref_setup[4] = dev_desc->touch_link; if (fwnode_property_present(chan_node, "azoteq,use-prox")) ref_setup[4] -= 2; + } else if (dev_desc->reg_grps[IQS7222_REG_GRP_TPAD].num_row && + fwnode_property_present(chan_node, + "azoteq,counts-filt-enable")) { + /* + * In the case of IQS7222D, however, the reference mode field + * is partially repurposed as a counts filter enable control. + */ + chan_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_REF; } if (fwnode_property_present(chan_node, "azoteq,rx-enable")) { @@ -2278,6 +2561,136 @@ static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222, IQS7222_REG_KEY_NO_WHEEL); } +static int iqs7222_parse_tpad(struct iqs7222_private *iqs7222, + struct fwnode_handle *tpad_node, int tpad_index) +{ + const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc; + struct touchscreen_properties *prop = &iqs7222->prop; + struct i2c_client *client = iqs7222->client; + int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row; + int count, error, i; + u16 *event_mask = &iqs7222->sys_setup[dev_desc->event_offset]; + u16 *tpad_setup = iqs7222->tpad_setup; + unsigned int chan_sel[12]; + + error = iqs7222_parse_props(iqs7222, tpad_node, tpad_index, + IQS7222_REG_GRP_TPAD, + IQS7222_REG_KEY_NONE); + if (error) + return error; + + count = fwnode_property_count_u32(tpad_node, "azoteq,channel-select"); + if (count < 0) { + dev_err(&client->dev, "Failed to count %s channels: %d\n", + fwnode_get_name(tpad_node), count); + return count; + } else if (!count || count > ARRAY_SIZE(chan_sel)) { + dev_err(&client->dev, "Invalid number of %s channels\n", + fwnode_get_name(tpad_node)); + return -EINVAL; + } + + error = fwnode_property_read_u32_array(tpad_node, + "azoteq,channel-select", + chan_sel, count); + if (error) { + dev_err(&client->dev, "Failed to read %s channels: %d\n", + fwnode_get_name(tpad_node), error); + return error; + } + + tpad_setup[6] &= ~GENMASK(num_chan - 1, 0); + + for (i = 0; i < ARRAY_SIZE(chan_sel); i++) { + tpad_setup[8 + i] = 0; + if (i >= count || chan_sel[i] == U8_MAX) + continue; + + if (chan_sel[i] >= num_chan) { + dev_err(&client->dev, "Invalid %s channel: %u\n", + fwnode_get_name(tpad_node), chan_sel[i]); + return -EINVAL; + } + + /* + * The following fields indicate which channels participate in + * the trackpad, as well as each channel's relative placement. + */ + tpad_setup[6] |= BIT(chan_sel[i]); + tpad_setup[8 + i] = chan_sel[i] * 34 + 1072; + } + + tpad_setup[7] = dev_desc->touch_link; + if (fwnode_property_present(tpad_node, "azoteq,use-prox")) + tpad_setup[7] -= 2; + + for (i = 0; i < ARRAY_SIZE(iqs7222_tp_events); i++) + tpad_setup[20] &= ~(iqs7222_tp_events[i].strict | + iqs7222_tp_events[i].enable); + + for (i = 0; i < ARRAY_SIZE(iqs7222_tp_events); i++) { + const char *event_name = iqs7222_tp_events[i].name; + struct fwnode_handle *event_node; + + event_node = fwnode_get_named_child_node(tpad_node, event_name); + if (!event_node) + continue; + + if (fwnode_property_present(event_node, + "azoteq,gesture-angle-tighten")) + tpad_setup[20] |= iqs7222_tp_events[i].strict; + + tpad_setup[20] |= iqs7222_tp_events[i].enable; + + error = iqs7222_parse_event(iqs7222, event_node, tpad_index, + IQS7222_REG_GRP_TPAD, + iqs7222_tp_events[i].reg_key, + iqs7222_tp_events[i].link, 1566, + NULL, + &iqs7222->tp_code[i]); + fwnode_handle_put(event_node); + if (error) + return error; + + if (!dev_desc->event_offset) + continue; + + /* + * The press/release event is determined based on whether the + * coordinate fields report 0xFFFF and solely relies on touch + * or proximity interrupts to be unmasked. + */ + if (i) + *event_mask |= IQS7222_EVENT_MASK_TPAD; + else if (tpad_setup[7] == dev_desc->touch_link) + *event_mask |= IQS7222_EVENT_MASK_TOUCH; + else + *event_mask |= IQS7222_EVENT_MASK_PROX; + } + + if (!iqs7222->tp_code[0]) + return 0; + + input_set_abs_params(iqs7222->keypad, ABS_X, + 0, (tpad_setup[4] ? : 1) - 1, 0, 0); + + input_set_abs_params(iqs7222->keypad, ABS_Y, + 0, (tpad_setup[5] ? : 1) - 1, 0, 0); + + touchscreen_parse_properties(iqs7222->keypad, false, prop); + + if (prop->max_x >= U16_MAX || prop->max_y >= U16_MAX) { + dev_err(&client->dev, "Invalid trackpad size: %u*%u\n", + prop->max_x, prop->max_y); + return -EINVAL; + } + + tpad_setup[4] = prop->max_x + 1; + tpad_setup[5] = prop->max_y + 1; + + return 0; +} + static int (*iqs7222_parse_extra[IQS7222_NUM_REG_GRPS]) (struct iqs7222_private *iqs7222, struct fwnode_handle *reg_grp_node, @@ -2285,6 +2698,7 @@ static int (*iqs7222_parse_extra[IQS7222_NUM_REG_GRPS]) [IQS7222_REG_GRP_CYCLE] = iqs7222_parse_cycle, [IQS7222_REG_GRP_CHAN] = iqs7222_parse_chan, [IQS7222_REG_GRP_SLDR] = iqs7222_parse_sldr, + [IQS7222_REG_GRP_TPAD] = iqs7222_parse_tpad, }; static int iqs7222_parse_reg_grp(struct iqs7222_private *iqs7222, @@ -2298,7 +2712,7 @@ static int iqs7222_parse_reg_grp(struct iqs7222_private *iqs7222, if (iqs7222_reg_grp_names[reg_grp]) { char reg_grp_name[16]; - snprintf(reg_grp_name, sizeof(reg_grp_name), "%s-%d", + snprintf(reg_grp_name, sizeof(reg_grp_name), iqs7222_reg_grp_names[reg_grp], reg_grp_index); reg_grp_node = device_get_named_child_node(&client->dev, @@ -2346,8 +2760,8 @@ static int iqs7222_parse_all(struct iqs7222_private *iqs7222) continue; /* - * The IQS7222C exposes multiple GPIO and must be informed - * as to which GPIO this group represents. + * The IQS7222C and IQS7222D expose multiple GPIO and must be + * informed as to which GPIO this group represents. */ for (j = 0; j < ARRAY_SIZE(iqs7222_gpio_links); j++) gpio_setup[0] &= ~BIT(iqs7222_gpio_links[j]); @@ -2480,6 +2894,41 @@ static int iqs7222_report(struct iqs7222_private *iqs7222) iqs7222->sl_code[i][j], 0); } + for (i = 0; i < dev_desc->reg_grps[IQS7222_REG_GRP_TPAD].num_row; i++) { + u16 tpad_pos_x = le16_to_cpu(status[4]); + u16 tpad_pos_y = le16_to_cpu(status[5]); + u16 state = le16_to_cpu(status[6]); + + input_report_key(iqs7222->keypad, iqs7222->tp_code[0], + tpad_pos_x < U16_MAX); + + if (tpad_pos_x < U16_MAX) + touchscreen_report_pos(iqs7222->keypad, &iqs7222->prop, + tpad_pos_x, tpad_pos_y, false); + + if (!(le16_to_cpu(status[1]) & IQS7222_EVENT_MASK_TPAD)) + continue; + + /* + * Skip the press/release event, as it does not have separate + * status fields and is handled separately. + */ + for (j = 1; j < ARRAY_SIZE(iqs7222_tp_events); j++) { + u16 mask = iqs7222_tp_events[j].mask; + u16 val = iqs7222_tp_events[j].val; + + input_report_key(iqs7222->keypad, + iqs7222->tp_code[j], + (state & mask) == val); + } + + input_sync(iqs7222->keypad); + + for (j = 1; j < ARRAY_SIZE(iqs7222_tp_events); j++) + input_report_key(iqs7222->keypad, + iqs7222->tp_code[j], 0); + } + input_sync(iqs7222->keypad); return 0; @@ -2584,6 +3033,7 @@ static const struct of_device_id iqs7222_of_match[] = { { .compatible = "azoteq,iqs7222a" }, { .compatible = "azoteq,iqs7222b" }, { .compatible = "azoteq,iqs7222c" }, + { .compatible = "azoteq,iqs7222d" }, { } }; MODULE_DEVICE_TABLE(of, iqs7222_of_match); @@ -2598,5 +3048,5 @@ static struct i2c_driver iqs7222_i2c_driver = { module_i2c_driver(iqs7222_i2c_driver); MODULE_AUTHOR("Jeff LaBundy "); -MODULE_DESCRIPTION("Azoteq IQS7222A/B/C Capacitive Touch Controller"); +MODULE_DESCRIPTION("Azoteq IQS7222A/B/C/D Capacitive Touch Controller"); MODULE_LICENSE("GPL"); -- GitLab From 2246ca53d7b3c286348c9c4cc4d2551972619cc2 Mon Sep 17 00:00:00 2001 From: Miaohe Lin Date: Sat, 1 Jul 2023 15:38:56 +0800 Subject: [PATCH 0046/3445] cgroup: remove unneeded return value of cgroup_rm_cftypes_locked() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The return value of cgroup_rm_cftypes_locked() is always 0. So remove it to simplify the code. No functional change intended. Signed-off-by: Miaohe Lin Reviewed-by: Michal Koutný Signed-off-by: Tejun Heo --- kernel/cgroup/cgroup.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index bfe3cd8ccf366..b0d98542eea29 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -4320,14 +4320,13 @@ static int cgroup_init_cftypes(struct cgroup_subsys *ss, struct cftype *cfts) return ret; } -static int cgroup_rm_cftypes_locked(struct cftype *cfts) +static void cgroup_rm_cftypes_locked(struct cftype *cfts) { lockdep_assert_held(&cgroup_mutex); list_del(&cfts->node); cgroup_apply_cftypes(cfts, false); cgroup_exit_cftypes(cfts); - return 0; } /** @@ -4343,8 +4342,6 @@ static int cgroup_rm_cftypes_locked(struct cftype *cfts) */ int cgroup_rm_cftypes(struct cftype *cfts) { - int ret; - if (!cfts || cfts[0].name[0] == '\0') return 0; @@ -4352,9 +4349,9 @@ int cgroup_rm_cftypes(struct cftype *cfts) return -ENOENT; cgroup_lock(); - ret = cgroup_rm_cftypes_locked(cfts); + cgroup_rm_cftypes_locked(cfts); cgroup_unlock(); - return ret; + return 0; } /** -- GitLab From 1299eb2b0ad5812dd6e5ea5b631da61f9e791bb3 Mon Sep 17 00:00:00 2001 From: Miaohe Lin Date: Thu, 6 Jul 2023 17:42:42 +0800 Subject: [PATCH 0047/3445] cgroup: minor cleanup for cgroup_extra_stat_show() Make it under CONFIG_CGROUP_SCHED to rid of __maybe_unused annotation. And further fetch cgrp inside cgroup_extra_stat_show() directly to rid of __maybe_unused annotation of cgrp. No functional change intended. Signed-off-by: Miaohe Lin Signed-off-by: Tejun Heo --- kernel/cgroup/cgroup.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index b0d98542eea29..4137eb4a30009 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -3654,9 +3654,10 @@ static int cgroup_stat_show(struct seq_file *seq, void *v) return 0; } -static int __maybe_unused cgroup_extra_stat_show(struct seq_file *seq, - struct cgroup *cgrp, int ssid) +#ifdef CONFIG_CGROUP_SCHED +static int cgroup_extra_stat_show(struct seq_file *seq, int ssid) { + struct cgroup *cgrp = seq_css(seq)->cgroup; struct cgroup_subsys *ss = cgroup_subsys[ssid]; struct cgroup_subsys_state *css; int ret; @@ -3672,15 +3673,15 @@ static int __maybe_unused cgroup_extra_stat_show(struct seq_file *seq, css_put(css); return ret; } +#endif static int cpu_stat_show(struct seq_file *seq, void *v) { - struct cgroup __maybe_unused *cgrp = seq_css(seq)->cgroup; int ret = 0; cgroup_base_stat_cputime_show(seq); #ifdef CONFIG_CGROUP_SCHED - ret = cgroup_extra_stat_show(seq, cgrp, cpu_cgrp_id); + ret = cgroup_extra_stat_show(seq, cpu_cgrp_id); #endif return ret; } -- GitLab From a453be9725a1aa3f602f5b4c66eefd1fb4ba7c44 Mon Sep 17 00:00:00 2001 From: Miaohe Lin Date: Tue, 4 Jul 2023 19:30:49 +0800 Subject: [PATCH 0048/3445] cgroup/cpuset: simplify the percpu kthreads check in update_tasks_cpumask() kthread_is_per_cpu() can be called directly without checking whether PF_KTHREAD is set in task->flags. So remove PF_KTHREAD check to make code more concise. Signed-off-by: Miaohe Lin Reviewed-by: Waiman Long Signed-off-by: Tejun Heo --- kernel/cgroup/cpuset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index 58e6f18f01c1b..601c40da8e033 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -1230,7 +1230,7 @@ static void update_tasks_cpumask(struct cpuset *cs, struct cpumask *new_cpus) /* * Percpu kthreads in top_cpuset are ignored */ - if ((task->flags & PF_KTHREAD) && kthread_is_per_cpu(task)) + if (kthread_is_per_cpu(task)) continue; cpumask_andnot(new_cpus, possible_mask, cs->subparts_cpus); } else { -- GitLab From 48f074565bb7eaa9ae502b2b2d423b1e50325e1b Mon Sep 17 00:00:00 2001 From: Miaohe Lin Date: Tue, 4 Jul 2023 20:03:52 +0800 Subject: [PATCH 0049/3445] cgroup/cpuset: avoid unneeded cpuset_mutex re-lock cpuset_mutex unlock and lock pair is only needed when transferring tasks out of empty cpuset. Avoid unneeded cpuset_mutex re-lock when !is_empty to save cpu cycles. Signed-off-by: Miaohe Lin Reviewed-by: Waiman Long Signed-off-by: Tejun Heo --- kernel/cgroup/cpuset.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index 601c40da8e033..e136269c152cb 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -3521,17 +3521,16 @@ hotplug_update_tasks_legacy(struct cpuset *cs, is_empty = cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed); - mutex_unlock(&cpuset_mutex); - /* * Move tasks to the nearest ancestor with execution resources, * This is full cgroup operation which will also call back into * cpuset. Should be done outside any lock. */ - if (is_empty) + if (is_empty) { + mutex_unlock(&cpuset_mutex); remove_tasks_in_empty_cpuset(cs); - - mutex_lock(&cpuset_mutex); + mutex_lock(&cpuset_mutex); + } } static void -- GitLab From 0a67b847e1f06a70a7b560b69a06b3c78d3e72f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Koutn=C3=BD?= Date: Mon, 3 Jul 2023 19:27:39 +0200 Subject: [PATCH 0050/3445] cpuset: Allow setscheduler regardless of manipulated task MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we migrate a task between two cgroups, one of the checks is a verification whether we can modify task's scheduler settings (cap_task_setscheduler()). An implicit migration occurs also when enabling a controller on the unified hierarchy (think of parent to child migration). The aforementioned check may be problematic if the caller of the migration (enabling a controller) has no permissions over migrated tasks. For instance, a user's cgroup that ends up running a process of a different user. Although cgroup permissions are configured favorably, the enablement fails due to the foreign process [1]. Change the behavior by relaxing the permissions check on the unified hierarchy when no effective change would happen. This is in accordance with unified hierarchy attachment behavior when permissions of the source to target cgroups are decisive whereas the migrated task is opaque (as opposed to more restrictive check in __cgroup1_procs_write()). Notice that foreign task's affinity may still be modified if the user can modify destination cgroup's cpuset attributes (update_tasks_cpumask() does no permissions check). The permissions check could thus be skipped on v2 even when affinity changes. Stay conservative in this patch though. [1] https://github.com/systemd/systemd/issues/18293#issuecomment-831205649 Signed-off-by: Michal Koutný Reviewed-by: Waiman Long Signed-off-by: Tejun Heo --- kernel/cgroup/cpuset.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index e136269c152cb..a46deb8a64dd7 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -2487,6 +2487,7 @@ static int cpuset_can_attach(struct cgroup_taskset *tset) struct cgroup_subsys_state *css; struct cpuset *cs, *oldcs; struct task_struct *task; + bool cpus_updated, mems_updated; int ret; /* used later by cpuset_attach() */ @@ -2501,13 +2502,25 @@ static int cpuset_can_attach(struct cgroup_taskset *tset) if (ret) goto out_unlock; + cpus_updated = !cpumask_equal(cs->effective_cpus, oldcs->effective_cpus); + mems_updated = !nodes_equal(cs->effective_mems, oldcs->effective_mems); + cgroup_taskset_for_each(task, css, tset) { ret = task_can_attach(task); if (ret) goto out_unlock; - ret = security_task_setscheduler(task); - if (ret) - goto out_unlock; + + /* + * Skip rights over task check in v2 when nothing changes, + * migration permission derives from hierarchy ownership in + * cgroup_procs_write_permission()). + */ + if (!cgroup_subsys_on_dfl(cpuset_cgrp_subsys) || + (cpus_updated || mems_updated)) { + ret = security_task_setscheduler(task); + if (ret) + goto out_unlock; + } if (dl_task(task)) { cs->nr_migrate_dl_tasks++; -- GitLab From 12101424d7d26131495bafc2ecfa17d39b8e3c64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Koutn=C3=BD?= Date: Mon, 3 Jul 2023 19:27:40 +0200 Subject: [PATCH 0051/3445] selftests: cgroup: Minor code reorganizations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No functional change intended, these small changes are merged into one commit and they serve as a preparation for an upcoming new testcase. Signed-off-by: Michal Koutný Reviewed-by: Waiman Long Signed-off-by: Tejun Heo --- MAINTAINERS | 1 + tools/testing/selftests/cgroup/cgroup_util.c | 2 ++ tools/testing/selftests/cgroup/cgroup_util.h | 2 ++ tools/testing/selftests/cgroup/test_core.c | 2 +- tools/testing/selftests/cgroup/test_cpuset_prs.sh | 2 +- 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 3be1bdfe8ecc7..318bd4e2d7f5d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5222,6 +5222,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git F: Documentation/admin-guide/cgroup-v1/cpusets.rst F: include/linux/cpuset.h F: kernel/cgroup/cpuset.c +F: tools/testing/selftests/cgroup/test_cpuset_prs.sh CONTROL GROUP - MEMORY RESOURCE CONTROLLER (MEMCG) M: Johannes Weiner diff --git a/tools/testing/selftests/cgroup/cgroup_util.c b/tools/testing/selftests/cgroup/cgroup_util.c index e8bbbdb77e0d5..0340d4ca8f51c 100644 --- a/tools/testing/selftests/cgroup/cgroup_util.c +++ b/tools/testing/selftests/cgroup/cgroup_util.c @@ -286,6 +286,8 @@ int cg_destroy(const char *cgroup) { int ret; + if (!cgroup) + return 0; retry: ret = rmdir(cgroup); if (ret && errno == EBUSY) { diff --git a/tools/testing/selftests/cgroup/cgroup_util.h b/tools/testing/selftests/cgroup/cgroup_util.h index c92df4e5d3958..1df7f202214af 100644 --- a/tools/testing/selftests/cgroup/cgroup_util.h +++ b/tools/testing/selftests/cgroup/cgroup_util.h @@ -11,6 +11,8 @@ #define USEC_PER_SEC 1000000L #define NSEC_PER_SEC 1000000000L +#define TEST_UID 65534 /* usually nobody, any !root is fine */ + /* * Checks if two given values differ by less than err% of their sum. */ diff --git a/tools/testing/selftests/cgroup/test_core.c b/tools/testing/selftests/cgroup/test_core.c index 6001235030631..80aa6b2373b96 100644 --- a/tools/testing/selftests/cgroup/test_core.c +++ b/tools/testing/selftests/cgroup/test_core.c @@ -683,7 +683,7 @@ cleanup: */ static int test_cgcore_lesser_euid_open(const char *root) { - const uid_t test_euid = 65534; /* usually nobody, any !root is fine */ + const uid_t test_euid = TEST_UID; int ret = KSFT_FAIL; char *cg_test_a = NULL, *cg_test_b = NULL; char *cg_test_a_procs = NULL, *cg_test_b_procs = NULL; diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh index 2b5215cc599f0..4afb132e4e4f3 100755 --- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh +++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh @@ -10,7 +10,7 @@ skip_test() { echo "$1" echo "Test SKIPPED" - exit 0 + exit 4 # ksft_skip } [[ $(id -u) -eq 0 ]] || skip_test "Test must be run as root!" -- GitLab From cd3c6f682df4df7de74a364c34b3b10f84db271b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Koutn=C3=BD?= Date: Mon, 3 Jul 2023 19:27:41 +0200 Subject: [PATCH 0052/3445] selftests: cgroup: Add cpuset migrations testcase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a separate testfile to verify treating permissions when tasks are migrated on cgroup v2 hierarchy between cpuset cgroups. In accordance with v2 design, migration should be allowed based on delegation boundaries (i.e. cgroup.procs permissions) and does not depend on the migrated object (i.e. unprivileged process can migrate another process (even privileged) as long as it remains in the original dedicated scope). Signed-off-by: Michal Koutný Signed-off-by: Tejun Heo --- MAINTAINERS | 1 + tools/testing/selftests/cgroup/.gitignore | 1 + tools/testing/selftests/cgroup/Makefile | 2 + tools/testing/selftests/cgroup/test_cpuset.c | 275 +++++++++++++++++++ 4 files changed, 279 insertions(+) create mode 100644 tools/testing/selftests/cgroup/test_cpuset.c diff --git a/MAINTAINERS b/MAINTAINERS index 318bd4e2d7f5d..86e9f56a89bf0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5222,6 +5222,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git F: Documentation/admin-guide/cgroup-v1/cpusets.rst F: include/linux/cpuset.h F: kernel/cgroup/cpuset.c +F: tools/testing/selftests/cgroup/test_cpuset.c F: tools/testing/selftests/cgroup/test_cpuset_prs.sh CONTROL GROUP - MEMORY RESOURCE CONTROLLER (MEMCG) diff --git a/tools/testing/selftests/cgroup/.gitignore b/tools/testing/selftests/cgroup/.gitignore index c4a57e69f749e..8443a8d46a1c6 100644 --- a/tools/testing/selftests/cgroup/.gitignore +++ b/tools/testing/selftests/cgroup/.gitignore @@ -5,4 +5,5 @@ test_freezer test_kmem test_kill test_cpu +test_cpuset wait_inotify diff --git a/tools/testing/selftests/cgroup/Makefile b/tools/testing/selftests/cgroup/Makefile index 3d263747d2ad0..dee0f013c7f40 100644 --- a/tools/testing/selftests/cgroup/Makefile +++ b/tools/testing/selftests/cgroup/Makefile @@ -12,6 +12,7 @@ TEST_GEN_PROGS += test_core TEST_GEN_PROGS += test_freezer TEST_GEN_PROGS += test_kill TEST_GEN_PROGS += test_cpu +TEST_GEN_PROGS += test_cpuset LOCAL_HDRS += $(selfdir)/clone3/clone3_selftests.h $(selfdir)/pidfd/pidfd.h @@ -23,3 +24,4 @@ $(OUTPUT)/test_core: cgroup_util.c $(OUTPUT)/test_freezer: cgroup_util.c $(OUTPUT)/test_kill: cgroup_util.c $(OUTPUT)/test_cpu: cgroup_util.c +$(OUTPUT)/test_cpuset: cgroup_util.c diff --git a/tools/testing/selftests/cgroup/test_cpuset.c b/tools/testing/selftests/cgroup/test_cpuset.c new file mode 100644 index 0000000000000..b061ed1e05b4d --- /dev/null +++ b/tools/testing/selftests/cgroup/test_cpuset.c @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +#include "../kselftest.h" +#include "cgroup_util.h" + +static int idle_process_fn(const char *cgroup, void *arg) +{ + (void)pause(); + return 0; +} + +static int do_migration_fn(const char *cgroup, void *arg) +{ + int object_pid = (int)(size_t)arg; + + if (setuid(TEST_UID)) + return EXIT_FAILURE; + + // XXX checking /proc/$pid/cgroup would be quicker than wait + if (cg_enter(cgroup, object_pid) || + cg_wait_for_proc_count(cgroup, 1)) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +} + +static int do_controller_fn(const char *cgroup, void *arg) +{ + const char *child = cgroup; + const char *parent = arg; + + if (setuid(TEST_UID)) + return EXIT_FAILURE; + + if (!cg_read_strstr(child, "cgroup.controllers", "cpuset")) + return EXIT_FAILURE; + + if (cg_write(parent, "cgroup.subtree_control", "+cpuset")) + return EXIT_FAILURE; + + if (cg_read_strstr(child, "cgroup.controllers", "cpuset")) + return EXIT_FAILURE; + + if (cg_write(parent, "cgroup.subtree_control", "-cpuset")) + return EXIT_FAILURE; + + if (!cg_read_strstr(child, "cgroup.controllers", "cpuset")) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +} + +/* + * Migrate a process between two sibling cgroups. + * The success should only depend on the parent cgroup permissions and not the + * migrated process itself (cpuset controller is in place because it uses + * security_task_setscheduler() in cgroup v1). + * + * Deliberately don't set cpuset.cpus in children to avoid definining migration + * permissions between two different cpusets. + */ +static int test_cpuset_perms_object(const char *root, bool allow) +{ + char *parent = NULL, *child_src = NULL, *child_dst = NULL; + char *parent_procs = NULL, *child_src_procs = NULL, *child_dst_procs = NULL; + const uid_t test_euid = TEST_UID; + int object_pid = 0; + int ret = KSFT_FAIL; + + parent = cg_name(root, "cpuset_test_0"); + if (!parent) + goto cleanup; + parent_procs = cg_name(parent, "cgroup.procs"); + if (!parent_procs) + goto cleanup; + if (cg_create(parent)) + goto cleanup; + + child_src = cg_name(parent, "cpuset_test_1"); + if (!child_src) + goto cleanup; + child_src_procs = cg_name(child_src, "cgroup.procs"); + if (!child_src_procs) + goto cleanup; + if (cg_create(child_src)) + goto cleanup; + + child_dst = cg_name(parent, "cpuset_test_2"); + if (!child_dst) + goto cleanup; + child_dst_procs = cg_name(child_dst, "cgroup.procs"); + if (!child_dst_procs) + goto cleanup; + if (cg_create(child_dst)) + goto cleanup; + + if (cg_write(parent, "cgroup.subtree_control", "+cpuset")) + goto cleanup; + + if (cg_read_strstr(child_src, "cgroup.controllers", "cpuset") || + cg_read_strstr(child_dst, "cgroup.controllers", "cpuset")) + goto cleanup; + + /* Enable permissions along src->dst tree path */ + if (chown(child_src_procs, test_euid, -1) || + chown(child_dst_procs, test_euid, -1)) + goto cleanup; + + if (allow && chown(parent_procs, test_euid, -1)) + goto cleanup; + + /* Fork a privileged child as a test object */ + object_pid = cg_run_nowait(child_src, idle_process_fn, NULL); + if (object_pid < 0) + goto cleanup; + + /* Carry out migration in a child process that can drop all privileges + * (including capabilities), the main process must remain privileged for + * cleanup. + * Child process's cgroup is irrelevant but we place it into child_dst + * as hacky way to pass information about migration target to the child. + */ + if (allow ^ (cg_run(child_dst, do_migration_fn, (void *)(size_t)object_pid) == EXIT_SUCCESS)) + goto cleanup; + + ret = KSFT_PASS; + +cleanup: + if (object_pid > 0) { + (void)kill(object_pid, SIGTERM); + (void)clone_reap(object_pid, WEXITED); + } + + cg_destroy(child_dst); + free(child_dst_procs); + free(child_dst); + + cg_destroy(child_src); + free(child_src_procs); + free(child_src); + + cg_destroy(parent); + free(parent_procs); + free(parent); + + return ret; +} + +static int test_cpuset_perms_object_allow(const char *root) +{ + return test_cpuset_perms_object(root, true); +} + +static int test_cpuset_perms_object_deny(const char *root) +{ + return test_cpuset_perms_object(root, false); +} + +/* + * Migrate a process between parent and child implicitely + * Implicit migration happens when a controller is enabled/disabled. + * + */ +static int test_cpuset_perms_subtree(const char *root) +{ + char *parent = NULL, *child = NULL; + char *parent_procs = NULL, *parent_subctl = NULL, *child_procs = NULL; + const uid_t test_euid = TEST_UID; + int object_pid = 0; + int ret = KSFT_FAIL; + + parent = cg_name(root, "cpuset_test_0"); + if (!parent) + goto cleanup; + parent_procs = cg_name(parent, "cgroup.procs"); + if (!parent_procs) + goto cleanup; + parent_subctl = cg_name(parent, "cgroup.subtree_control"); + if (!parent_subctl) + goto cleanup; + if (cg_create(parent)) + goto cleanup; + + child = cg_name(parent, "cpuset_test_1"); + if (!child) + goto cleanup; + child_procs = cg_name(child, "cgroup.procs"); + if (!child_procs) + goto cleanup; + if (cg_create(child)) + goto cleanup; + + /* Enable permissions as in a delegated subtree */ + if (chown(parent_procs, test_euid, -1) || + chown(parent_subctl, test_euid, -1) || + chown(child_procs, test_euid, -1)) + goto cleanup; + + /* Put a privileged child in the subtree and modify controller state + * from an unprivileged process, the main process remains privileged + * for cleanup. + * The unprivileged child runs in subtree too to avoid parent and + * internal-node constraing violation. + */ + object_pid = cg_run_nowait(child, idle_process_fn, NULL); + if (object_pid < 0) + goto cleanup; + + if (cg_run(child, do_controller_fn, parent) != EXIT_SUCCESS) + goto cleanup; + + ret = KSFT_PASS; + +cleanup: + if (object_pid > 0) { + (void)kill(object_pid, SIGTERM); + (void)clone_reap(object_pid, WEXITED); + } + + cg_destroy(child); + free(child_procs); + free(child); + + cg_destroy(parent); + free(parent_subctl); + free(parent_procs); + free(parent); + + return ret; +} + + +#define T(x) { x, #x } +struct cpuset_test { + int (*fn)(const char *root); + const char *name; +} tests[] = { + T(test_cpuset_perms_object_allow), + T(test_cpuset_perms_object_deny), + T(test_cpuset_perms_subtree), +}; +#undef T + +int main(int argc, char *argv[]) +{ + char root[PATH_MAX]; + int i, ret = EXIT_SUCCESS; + + if (cg_find_unified_root(root, sizeof(root))) + ksft_exit_skip("cgroup v2 isn't mounted\n"); + + if (cg_read_strstr(root, "cgroup.subtree_control", "cpuset")) + if (cg_write(root, "cgroup.subtree_control", "+cpuset")) + ksft_exit_skip("Failed to set cpuset controller\n"); + + for (i = 0; i < ARRAY_SIZE(tests); i++) { + switch (tests[i].fn(root)) { + case KSFT_PASS: + ksft_test_result_pass("%s\n", tests[i].name); + break; + case KSFT_SKIP: + ksft_test_result_skip("%s\n", tests[i].name); + break; + default: + ret = EXIT_FAILURE; + ksft_test_result_fail("%s\n", tests[i].name); + break; + } + } + + return ret; +} -- GitLab From 20bdedafd2f63e0ba70991127f9b5c0826ebdb32 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Fri, 30 Jun 2023 21:28:53 +0900 Subject: [PATCH 0053/3445] workqueue: Warn attempt to flush system-wide workqueues. Based on commit c4f135d643823a86 ("workqueue: Wrap flush_workqueue() using a macro"), all in-tree users stopped flushing system-wide workqueues. Therefore, start emitting runtime message so that all out-of-tree users will understand that they need to update their code. Signed-off-by: Tetsuo Handa Signed-off-by: Tejun Heo --- include/linux/workqueue.h | 44 +++------------------------------------ kernel/workqueue.c | 11 +++++----- 2 files changed, 8 insertions(+), 47 deletions(-) diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 683efe29fa698..1a4223cbdb5f2 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -569,6 +569,7 @@ static inline bool schedule_work(struct work_struct *work) /* * Detect attempt to flush system-wide workqueues at compile time when possible. + * Warn attempt to flush system-wide workqueues at runtime. * * See https://lkml.kernel.org/r/49925af7-78a8-a3dd-bce6-cfc02e1a9236@I-love.SAKURA.ne.jp * for reasons and steps for converting system-wide workqueues into local workqueues. @@ -576,52 +577,13 @@ static inline bool schedule_work(struct work_struct *work) extern void __warn_flushing_systemwide_wq(void) __compiletime_warning("Please avoid flushing system-wide workqueues."); -/** - * flush_scheduled_work - ensure that any scheduled work has run to completion. - * - * Forces execution of the kernel-global workqueue and blocks until its - * completion. - * - * It's very easy to get into trouble if you don't take great care. - * Either of the following situations will lead to deadlock: - * - * One of the work items currently on the workqueue needs to acquire - * a lock held by your code or its caller. - * - * Your code is running in the context of a work routine. - * - * They will be detected by lockdep when they occur, but the first might not - * occur very often. It depends on what work items are on the workqueue and - * what locks they need, which you have no control over. - * - * In most situations flushing the entire workqueue is overkill; you merely - * need to know that a particular work item isn't queued and isn't running. - * In such cases you should use cancel_delayed_work_sync() or - * cancel_work_sync() instead. - * - * Please stop calling this function! A conversion to stop flushing system-wide - * workqueues is in progress. This function will be removed after all in-tree - * users stopped calling this function. - */ -/* - * The background of commit 771c035372a036f8 ("deprecate the - * '__deprecated' attribute warnings entirely and for good") is that, - * since Linus builds all modules between every single pull he does, - * the standard kernel build needs to be _clean_ in order to be able to - * notice when new problems happen. Therefore, don't emit warning while - * there are in-tree users. - */ +/* Please stop using this function, for this function will be removed in near future. */ #define flush_scheduled_work() \ ({ \ - if (0) \ - __warn_flushing_systemwide_wq(); \ + __warn_flushing_systemwide_wq(); \ __flush_workqueue(system_wq); \ }) -/* - * Although there is no longer in-tree caller, for now just emit warning - * in order to give out-of-tree callers time to update. - */ #define flush_workqueue(wq) \ ({ \ struct workqueue_struct *_wq = (wq); \ diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 02a8f402eeb54..f8891552fdd6d 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -6571,10 +6571,9 @@ void __init workqueue_init(void) wq_watchdog_init(); } -/* - * Despite the naming, this is a no-op function which is here only for avoiding - * link error. Since compile-time warning may fail to catch, we will need to - * emit run-time warning from __flush_workqueue(). - */ -void __warn_flushing_systemwide_wq(void) { } +void __warn_flushing_systemwide_wq(void) +{ + pr_warn("WARNING: Flushing system-wide workqueues will be prohibited in near future.\n"); + dump_stack(); +} EXPORT_SYMBOL(__warn_flushing_systemwide_wq); -- GitLab From ace3c5499e61ef7c0433a7a297227a9bdde54a55 Mon Sep 17 00:00:00 2001 From: tiozhang Date: Thu, 29 Jun 2023 11:50:50 +0800 Subject: [PATCH 0054/3445] workqueue: add cmdline parameter `workqueue.unbound_cpus` to further constrain wq_unbound_cpumask at boot time Motivation of doing this is to better improve boot times for devices when we want to prevent our workqueue works from running on some specific CPUs, e,g, some CPUs are busy with interrupts. Signed-off-by: tiozhang Signed-off-by: Tejun Heo --- Documentation/admin-guide/kernel-parameters.txt | 7 +++++++ kernel/workqueue.c | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index a1457995fd41c..d1edee0fd5ec3 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -6964,6 +6964,13 @@ disables both lockup detectors. Default is 10 seconds. + workqueue.unbound_cpus= + [KNL,SMP] Specify to constrain one or some CPUs + to use in unbound workqueues. + Format: + By default, all online CPUs are available for + unbound workqueues. + workqueue.watchdog_thresh= If CONFIG_WQ_WATCHDOG is configured, workqueue can warn stall conditions and dump internal state to diff --git a/kernel/workqueue.c b/kernel/workqueue.c index f8891552fdd6d..83f8993af57cf 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -368,6 +368,9 @@ static bool workqueue_freezing; /* PL: have wqs started freezing? */ /* PL&A: allowable cpus for unbound wqs and work items */ static cpumask_var_t wq_unbound_cpumask; +/* for further constrain wq_unbound_cpumask by cmdline parameter*/ +static struct cpumask wq_cmdline_cpumask __initdata; + /* CPU where unbound work was last round robin scheduled from this CPU */ static DEFINE_PER_CPU(int, wq_rr_cpu_last); @@ -6455,6 +6458,9 @@ void __init workqueue_init_early(void) cpumask_copy(wq_unbound_cpumask, housekeeping_cpumask(HK_TYPE_WQ)); cpumask_and(wq_unbound_cpumask, wq_unbound_cpumask, housekeeping_cpumask(HK_TYPE_DOMAIN)); + if (!cpumask_empty(&wq_cmdline_cpumask)) + cpumask_and(wq_unbound_cpumask, wq_unbound_cpumask, &wq_cmdline_cpumask); + pwq_cache = KMEM_CACHE(pool_workqueue, SLAB_PANIC); /* initialize CPU pools */ @@ -6577,3 +6583,14 @@ void __warn_flushing_systemwide_wq(void) dump_stack(); } EXPORT_SYMBOL(__warn_flushing_systemwide_wq); + +static int __init workqueue_unbound_cpus_setup(char *str) +{ + if (cpulist_parse(str, &wq_cmdline_cpumask) < 0) { + cpumask_clear(&wq_cmdline_cpumask); + pr_warn("workqueue.unbound_cpus: incorrect CPU range, using default\n"); + } + + return 1; +} +__setup("workqueue.unbound_cpus=", workqueue_unbound_cpus_setup); -- GitLab From 868f87b3759bb7bedb081fdd40ef8d143c003fa6 Mon Sep 17 00:00:00 2001 From: Miaohe Lin Date: Tue, 27 Jun 2023 19:40:59 +0800 Subject: [PATCH 0055/3445] cgroup: fix obsolete comment above for_each_css() cgroup_tree_mutex is removed since commit 8353da1f91f1 ("cgroup: remove cgroup_tree_mutex"), update corresponding comment. Signed-off-by: Miaohe Lin Signed-off-by: Tejun Heo --- kernel/cgroup/cgroup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 4137eb4a30009..13d9ea33eb6d5 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -679,7 +679,7 @@ EXPORT_SYMBOL_GPL(of_css); * @ssid: the index of the subsystem, CGROUP_SUBSYS_COUNT after reaching the end * @cgrp: the target cgroup to iterate css's of * - * Should be called under cgroup_[tree_]mutex. + * Should be called under cgroup_mutex. */ #define for_each_css(css, ssid, cgrp) \ for ((ssid) = 0; (ssid) < CGROUP_SUBSYS_COUNT; (ssid)++) \ -- GitLab From c8c926200c55454101f072a4b16c9ff5b8c9e56f Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Tue, 27 Jun 2023 10:35:00 -0400 Subject: [PATCH 0056/3445] cgroup/cpuset: Inherit parent's load balance state in v2 Since commit f28e22441f35 ("cgroup/cpuset: Add a new isolated cpus.partition type"), the CS_SCHED_LOAD_BALANCE bit of a v2 cpuset can be on or off. The child cpusets of a partition root must have the same setting as its parent or it may screw up the rebuilding of sched domains. Fix this problem by making sure the a child v2 cpuset will follows its parent cpuset load balance state unless the child cpuset is a new partition root itself. Fixes: f28e22441f35 ("cgroup/cpuset: Add a new isolated cpus.partition type") Signed-off-by: Waiman Long Signed-off-by: Tejun Heo --- kernel/cgroup/cpuset.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index a46deb8a64dd7..71e4b5b836145 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -1588,11 +1588,16 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp, } /* - * Skip the whole subtree if the cpumask remains the same - * and has no partition root state and force flag not set. + * Skip the whole subtree if + * 1) the cpumask remains the same, + * 2) has no partition root state, + * 3) force flag not set, and + * 4) for v2 load balance state same as its parent. */ if (!cp->partition_root_state && !force && - cpumask_equal(tmp->new_cpus, cp->effective_cpus)) { + cpumask_equal(tmp->new_cpus, cp->effective_cpus) && + (!cgroup_subsys_on_dfl(cpuset_cgrp_subsys) || + (is_sched_load_balance(parent) == is_sched_load_balance(cp)))) { pos_css = css_rightmost_descendant(pos_css); continue; } @@ -1675,6 +1680,20 @@ update_parent_subparts: update_tasks_cpumask(cp, tmp->new_cpus); + /* + * On default hierarchy, inherit the CS_SCHED_LOAD_BALANCE + * from parent if current cpuset isn't a valid partition root + * and their load balance states differ. + */ + if (cgroup_subsys_on_dfl(cpuset_cgrp_subsys) && + !is_partition_valid(cp) && + (is_sched_load_balance(parent) != is_sched_load_balance(cp))) { + if (is_sched_load_balance(parent)) + set_bit(CS_SCHED_LOAD_BALANCE, &cp->flags); + else + clear_bit(CS_SCHED_LOAD_BALANCE, &cp->flags); + } + /* * On legacy hierarchy, if the effective cpumask of any non- * empty cpuset is changed, we need to rebuild sched domains. @@ -3235,6 +3254,14 @@ static int cpuset_css_online(struct cgroup_subsys_state *css) cs->use_parent_ecpus = true; parent->child_ecpus_count++; } + + /* + * For v2, clear CS_SCHED_LOAD_BALANCE if parent is isolated + */ + if (cgroup_subsys_on_dfl(cpuset_cgrp_subsys) && + !is_sched_load_balance(parent)) + clear_bit(CS_SCHED_LOAD_BALANCE, &cs->flags); + spin_unlock_irq(&callback_lock); if (!test_bit(CGRP_CPUSET_CLONE_CHILDREN, &css->cgroup->flags)) -- GitLab From a86ce68078b200a5dcc263da01154ee926c25188 Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Tue, 27 Jun 2023 10:35:01 -0400 Subject: [PATCH 0057/3445] cgroup/cpuset: Extract out CS_CPU_EXCLUSIVE & CS_SCHED_LOAD_BALANCE handling Extract out the setting of CS_CPU_EXCLUSIVE and CS_SCHED_LOAD_BALANCE flags as well as the rebuilding of scheduling domains into the new update_partition_exclusive() and update_partition_sd_lb() helper functions to simplify the logic. The update_partition_exclusive() helper is called mainly at the beginning of the caller, but it may be called at the end too. The update_partition_sd_lb() helper is called at the end of the caller. This patch should reduce the chance that cpuset partition will end up in an incorrect state. Signed-off-by: Waiman Long Signed-off-by: Tejun Heo --- kernel/cgroup/cpuset.c | 141 +++++++++++++++++++++++++---------------- 1 file changed, 86 insertions(+), 55 deletions(-) diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index 71e4b5b836145..d8d3b750c1386 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -1255,7 +1255,7 @@ static void update_tasks_cpumask(struct cpuset *cs, struct cpumask *new_cpus) static void compute_effective_cpumask(struct cpumask *new_cpus, struct cpuset *cs, struct cpuset *parent) { - if (parent->nr_subparts_cpus) { + if (parent->nr_subparts_cpus && is_partition_valid(cs)) { cpumask_or(new_cpus, parent->effective_cpus, parent->subparts_cpus); cpumask_and(new_cpus, new_cpus, cs->cpus_allowed); @@ -1277,6 +1277,50 @@ enum subparts_cmd { static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, int turning_on); + +/* + * Update partition exclusive flag + * + * Return: 0 if successful, an error code otherwise + */ +static int update_partition_exclusive(struct cpuset *cs, int new_prs) +{ + bool exclusive = (new_prs > 0); + + if (exclusive && !is_cpu_exclusive(cs)) { + if (update_flag(CS_CPU_EXCLUSIVE, cs, 1)) + return PERR_NOTEXCL; + } else if (!exclusive && is_cpu_exclusive(cs)) { + /* Turning off CS_CPU_EXCLUSIVE will not return error */ + update_flag(CS_CPU_EXCLUSIVE, cs, 0); + } + return 0; +} + +/* + * Update partition load balance flag and/or rebuild sched domain + * + * Changing load balance flag will automatically call + * rebuild_sched_domains_locked(). + */ +static void update_partition_sd_lb(struct cpuset *cs, int old_prs) +{ + int new_prs = cs->partition_root_state; + bool new_lb = (new_prs != PRS_ISOLATED); + bool rebuild_domains = (new_prs > 0) || (old_prs > 0); + + if (new_lb != !!is_sched_load_balance(cs)) { + rebuild_domains = true; + if (new_lb) + set_bit(CS_SCHED_LOAD_BALANCE, &cs->flags); + else + clear_bit(CS_SCHED_LOAD_BALANCE, &cs->flags); + } + + if (rebuild_domains) + rebuild_sched_domains_locked(); +} + /** * update_parent_subparts_cpumask - update subparts_cpus mask of parent cpuset * @cs: The cpuset that requests change in partition root state @@ -1336,8 +1380,7 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd, return is_partition_invalid(parent) ? PERR_INVPARENT : PERR_NOTPART; } - if ((newmask && cpumask_empty(newmask)) || - (!newmask && cpumask_empty(cs->cpus_allowed))) + if (!newmask && cpumask_empty(cs->cpus_allowed)) return PERR_CPUSEMPTY; /* @@ -1403,11 +1446,16 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd, cpumask_and(tmp->addmask, newmask, parent->cpus_allowed); adding = cpumask_andnot(tmp->addmask, tmp->addmask, parent->subparts_cpus); + /* + * Empty cpumask is not allewed + */ + if (cpumask_empty(newmask)) { + part_error = PERR_CPUSEMPTY; /* * Make partition invalid if parent's effective_cpus could * become empty and there are tasks in the parent. */ - if (adding && + } else if (adding && cpumask_subset(parent->effective_cpus, tmp->addmask) && !cpumask_intersects(tmp->delmask, cpu_active_mask) && partition_is_populated(parent, cs)) { @@ -1480,14 +1528,13 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd, /* * Transitioning between invalid to valid or vice versa may require - * changing CS_CPU_EXCLUSIVE and CS_SCHED_LOAD_BALANCE. + * changing CS_CPU_EXCLUSIVE. */ if (old_prs != new_prs) { - if (is_prs_invalid(old_prs) && !is_cpu_exclusive(cs) && - (update_flag(CS_CPU_EXCLUSIVE, cs, 1) < 0)) - return PERR_NOTEXCL; - if (is_prs_invalid(new_prs) && is_cpu_exclusive(cs)) - update_flag(CS_CPU_EXCLUSIVE, cs, 0); + int err = update_partition_exclusive(cs, new_prs); + + if (err) + return err; } /* @@ -1524,15 +1571,16 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd, update_tasks_cpumask(parent, tmp->addmask); /* - * Set or clear CS_SCHED_LOAD_BALANCE when partcmd_update, if necessary. - * rebuild_sched_domains_locked() may be called. + * For partcmd_update without newmask, it is being called from + * cpuset_hotplug_workfn() where cpus_read_lock() wasn't taken. + * Update the load balance flag and scheduling domain if + * cpus_read_trylock() is successful. */ - if (old_prs != new_prs) { - if (old_prs == PRS_ISOLATED) - update_flag(CS_SCHED_LOAD_BALANCE, cs, 1); - else if (new_prs == PRS_ISOLATED) - update_flag(CS_SCHED_LOAD_BALANCE, cs, 0); + if ((cmd == partcmd_update) && !newmask && cpus_read_trylock()) { + update_partition_sd_lb(cs, old_prs); + cpus_read_unlock(); } + notify_partition_change(cs, old_prs); return 0; } @@ -1766,6 +1814,7 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs, int retval; struct tmpmasks tmp; bool invalidate = false; + int old_prs = cs->partition_root_state; /* top_cpuset.cpus_allowed tracks cpu_online_mask; it's read-only */ if (cs == &top_cpuset) @@ -1885,6 +1934,9 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs, */ if (parent->child_ecpus_count) update_sibling_cpumasks(parent, cs, &tmp); + + /* Update CS_SCHED_LOAD_BALANCE and/or sched_domains */ + update_partition_sd_lb(cs, old_prs); } return 0; } @@ -2261,7 +2313,6 @@ out: static int update_prstate(struct cpuset *cs, int new_prs) { int err = PERR_NONE, old_prs = cs->partition_root_state; - bool sched_domain_rebuilt = false; struct cpuset *parent = parent_cs(cs); struct tmpmasks tmpmask; @@ -2280,45 +2331,28 @@ static int update_prstate(struct cpuset *cs, int new_prs) if (alloc_cpumasks(NULL, &tmpmask)) return -ENOMEM; + err = update_partition_exclusive(cs, new_prs); + if (err) + goto out; + if (!old_prs) { /* - * Turning on partition root requires setting the - * CS_CPU_EXCLUSIVE bit implicitly as well and cpus_allowed - * cannot be empty. + * cpus_allowed cannot be empty. */ if (cpumask_empty(cs->cpus_allowed)) { err = PERR_CPUSEMPTY; goto out; } - err = update_flag(CS_CPU_EXCLUSIVE, cs, 1); - if (err) { - err = PERR_NOTEXCL; - goto out; - } - err = update_parent_subparts_cpumask(cs, partcmd_enable, NULL, &tmpmask); - if (err) { - update_flag(CS_CPU_EXCLUSIVE, cs, 0); + if (err) goto out; - } - - if (new_prs == PRS_ISOLATED) { - /* - * Disable the load balance flag should not return an - * error unless the system is running out of memory. - */ - update_flag(CS_SCHED_LOAD_BALANCE, cs, 0); - sched_domain_rebuilt = true; - } } else if (old_prs && new_prs) { /* * A change in load balance state only, no change in cpumasks. */ - update_flag(CS_SCHED_LOAD_BALANCE, cs, (new_prs != PRS_ISOLATED)); - sched_domain_rebuilt = true; - goto out; /* Sched domain is rebuilt in update_flag() */ + goto out; } else { /* * Switching back to member is always allowed even if it @@ -2337,15 +2371,6 @@ static int update_prstate(struct cpuset *cs, int new_prs) compute_effective_cpumask(cs->effective_cpus, cs, parent); spin_unlock_irq(&callback_lock); } - - /* Turning off CS_CPU_EXCLUSIVE will not return error */ - update_flag(CS_CPU_EXCLUSIVE, cs, 0); - - if (!is_sched_load_balance(cs)) { - /* Make sure load balance is on */ - update_flag(CS_SCHED_LOAD_BALANCE, cs, 1); - sched_domain_rebuilt = true; - } } update_tasks_cpumask(parent, tmpmask.new_cpus); @@ -2353,18 +2378,21 @@ static int update_prstate(struct cpuset *cs, int new_prs) if (parent->child_ecpus_count) update_sibling_cpumasks(parent, cs, &tmpmask); - if (!sched_domain_rebuilt) - rebuild_sched_domains_locked(); out: /* - * Make partition invalid if an error happen + * Make partition invalid & disable CS_CPU_EXCLUSIVE if an error + * happens. */ - if (err) + if (err) { new_prs = -new_prs; + update_partition_exclusive(cs, new_prs); + } + spin_lock_irq(&callback_lock); cs->partition_root_state = new_prs; WRITE_ONCE(cs->prs_err, err); spin_unlock_irq(&callback_lock); + /* * Update child cpusets, if present. * Force update if switching back to member. @@ -2372,6 +2400,9 @@ out: if (!list_empty(&cs->css.children)) update_cpumasks_hier(cs, &tmpmask, !new_prs); + /* Update sched domains and load balance flag */ + update_partition_sd_lb(cs, old_prs); + notify_partition_change(cs, old_prs); free_cpumasks(NULL, &tmpmask); return 0; -- GitLab From 99fe36ba6fc16aa0962bc1f41ebcdec696203889 Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Tue, 27 Jun 2023 10:35:02 -0400 Subject: [PATCH 0058/3445] cgroup/cpuset: Improve temporary cpumasks handling The limitation that update_parent_subparts_cpumask() can only use addmask & delmask in the given tmp cpumasks is fragile and may lead to unexpected error. Fix this problem by allocating/freeing a struct tmpmasks in update_cpumask() to avoid reusing the cpumasks in trial_cs. With this change, we can move the update_tasks_cpumask() for the parent and update_sibling_cpumasks() for the sibling to inside update_parent_subparts_cpumask(). Signed-off-by: Waiman Long Signed-off-by: Tejun Heo --- kernel/cgroup/cpuset.c | 42 +++++++++++++----------------------------- 1 file changed, 13 insertions(+), 29 deletions(-) diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index d8d3b750c1386..c9bb44e50eb21 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -1277,6 +1277,8 @@ enum subparts_cmd { static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, int turning_on); +static void update_sibling_cpumasks(struct cpuset *parent, struct cpuset *cs, + struct tmpmasks *tmp); /* * Update partition exclusive flag @@ -1447,7 +1449,7 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd, adding = cpumask_andnot(tmp->addmask, tmp->addmask, parent->subparts_cpus); /* - * Empty cpumask is not allewed + * Empty cpumask is not allowed */ if (cpumask_empty(newmask)) { part_error = PERR_CPUSEMPTY; @@ -1567,8 +1569,11 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd, spin_unlock_irq(&callback_lock); - if (adding || deleting) + if (adding || deleting) { update_tasks_cpumask(parent, tmp->addmask); + if (parent->child_ecpus_count) + update_sibling_cpumasks(parent, cs, tmp); + } /* * For partcmd_update without newmask, it is being called from @@ -1842,18 +1847,8 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs, if (cpumask_equal(cs->cpus_allowed, trialcs->cpus_allowed)) return 0; -#ifdef CONFIG_CPUMASK_OFFSTACK - /* - * Use the cpumasks in trialcs for tmpmasks when they are pointers - * to allocated cpumasks. - * - * Note that update_parent_subparts_cpumask() uses only addmask & - * delmask, but not new_cpus. - */ - tmp.addmask = trialcs->subparts_cpus; - tmp.delmask = trialcs->effective_cpus; - tmp.new_cpus = NULL; -#endif + if (alloc_cpumasks(NULL, &tmp)) + return -ENOMEM; retval = validate_change(cs, trialcs); @@ -1882,7 +1877,7 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs, retval = 0; } if (retval < 0) - return retval; + goto out_free; if (cs->partition_root_state) { if (invalidate) @@ -1917,11 +1912,6 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs, } spin_unlock_irq(&callback_lock); -#ifdef CONFIG_CPUMASK_OFFSTACK - /* Now trialcs->cpus_allowed is available */ - tmp.new_cpus = trialcs->cpus_allowed; -#endif - /* effective_cpus will be updated here */ update_cpumasks_hier(cs, &tmp, false); @@ -1938,6 +1928,8 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs, /* Update CS_SCHED_LOAD_BALANCE and/or sched_domains */ update_partition_sd_lb(cs, old_prs); } +out_free: + free_cpumasks(NULL, &tmp); return 0; } @@ -2346,13 +2338,11 @@ static int update_prstate(struct cpuset *cs, int new_prs) err = update_parent_subparts_cpumask(cs, partcmd_enable, NULL, &tmpmask); - if (err) - goto out; } else if (old_prs && new_prs) { /* * A change in load balance state only, no change in cpumasks. */ - goto out; + ; } else { /* * Switching back to member is always allowed even if it @@ -2372,12 +2362,6 @@ static int update_prstate(struct cpuset *cs, int new_prs) spin_unlock_irq(&callback_lock); } } - - update_tasks_cpumask(parent, tmpmask.new_cpus); - - if (parent->child_ecpus_count) - update_sibling_cpumasks(parent, cs, &tmpmask); - out: /* * Make partition invalid & disable CS_CPU_EXCLUSIVE if an error -- GitLab From 3ae0b773211ed0231e7ee3e8d28ec4ab9bc5134b Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Tue, 27 Jun 2023 10:35:03 -0400 Subject: [PATCH 0059/3445] cgroup/cpuset: Allow suppression of sched domain rebuild in update_cpumasks_hier() A single partition setup and tear-down operation can lead to multiple rebuild_sched_domains_locked() calls which is a waste of effort. This can partly be mitigated by adding a flag to suppress the rebuild_sched_domains_locked() call in update_cpumasks_hier(). Since a Boolean flag has already been passed as the 3rd argument to update_cpumasks_hier(), we can extend that to a full flag word. The sched domain rebuild suppression is now enabled in update_sibling_cpumasks() as all it callers will do the sched domain rebuild after its return later on anyway. Signed-off-by: Waiman Long Signed-off-by: Tejun Heo --- kernel/cgroup/cpuset.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index c9bb44e50eb21..b278b60ed788d 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -1590,6 +1590,12 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd, return 0; } +/* + * update_cpumasks_hier() flags + */ +#define HIER_CHECKALL 0x01 /* Check all cpusets with no skipping */ +#define HIER_NO_SD_REBUILD 0x02 /* Don't rebuild sched domains */ + /* * update_cpumasks_hier - Update effective cpumasks and tasks in the subtree * @cs: the cpuset to consider @@ -1604,7 +1610,7 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd, * Called with cpuset_mutex held */ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp, - bool force) + int flags) { struct cpuset *cp; struct cgroup_subsys_state *pos_css; @@ -1644,10 +1650,10 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp, * Skip the whole subtree if * 1) the cpumask remains the same, * 2) has no partition root state, - * 3) force flag not set, and + * 3) HIER_CHECKALL flag not set, and * 4) for v2 load balance state same as its parent. */ - if (!cp->partition_root_state && !force && + if (!cp->partition_root_state && !(flags & HIER_CHECKALL) && cpumask_equal(tmp->new_cpus, cp->effective_cpus) && (!cgroup_subsys_on_dfl(cpuset_cgrp_subsys) || (is_sched_load_balance(parent) == is_sched_load_balance(cp)))) { @@ -1764,7 +1770,7 @@ update_parent_subparts: } rcu_read_unlock(); - if (need_rebuild_sched_domains) + if (need_rebuild_sched_domains && !(flags & HIER_NO_SD_REBUILD)) rebuild_sched_domains_locked(); } @@ -1788,7 +1794,9 @@ static void update_sibling_cpumasks(struct cpuset *parent, struct cpuset *cs, * to use the right effective_cpus value. * * The update_cpumasks_hier() function may sleep. So we have to - * release the RCU read lock before calling it. + * release the RCU read lock before calling it. HIER_NO_SD_REBUILD + * flag is used to suppress rebuild of sched domains as the callers + * will take care of that. */ rcu_read_lock(); cpuset_for_each_child(sibling, pos_css, parent) { @@ -1800,7 +1808,7 @@ static void update_sibling_cpumasks(struct cpuset *parent, struct cpuset *cs, continue; rcu_read_unlock(); - update_cpumasks_hier(sibling, tmp, false); + update_cpumasks_hier(sibling, tmp, HIER_NO_SD_REBUILD); rcu_read_lock(); css_put(&sibling->css); } @@ -1913,7 +1921,7 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs, spin_unlock_irq(&callback_lock); /* effective_cpus will be updated here */ - update_cpumasks_hier(cs, &tmp, false); + update_cpumasks_hier(cs, &tmp, 0); if (cs->partition_root_state) { struct cpuset *parent = parent_cs(cs); @@ -2382,7 +2390,7 @@ out: * Force update if switching back to member. */ if (!list_empty(&cs->css.children)) - update_cpumasks_hier(cs, &tmpmask, !new_prs); + update_cpumasks_hier(cs, &tmpmask, !new_prs ? HIER_CHECKALL : 0); /* Update sched domains and load balance flag */ update_partition_sd_lb(cs, old_prs); -- GitLab From 5abb32411f221a000ff3d05bea31b4ce61cc6236 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 13:35:30 -0700 Subject: [PATCH 0060/3445] Input: bcm-keypad - convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230705052346.39337-1-frank.li@vivo.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/bcm-keypad.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/input/keyboard/bcm-keypad.c b/drivers/input/keyboard/bcm-keypad.c index 05b09066df849..0aa6ef0da0eea 100644 --- a/drivers/input/keyboard/bcm-keypad.c +++ b/drivers/input/keyboard/bcm-keypad.c @@ -307,7 +307,6 @@ static int bcm_kp_probe(struct platform_device *pdev) { struct bcm_kp *kp; struct input_dev *input_dev; - struct resource *res; int error; kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL); @@ -353,14 +352,7 @@ static int bcm_kp_probe(struct platform_device *pdev) return error; } - /* Get the KEYPAD base address */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Missing keypad base address resource\n"); - return -ENODEV; - } - - kp->base = devm_ioremap_resource(&pdev->dev, res); + kp->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(kp->base)) return PTR_ERR(kp->base); -- GitLab From 3799836f606fdd85acd6807ed52032ab2ea3bce2 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 15:26:06 -0700 Subject: [PATCH 0061/3445] Input: lpc32xx-keys - convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230705052346.39337-2-frank.li@vivo.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/lpc32xx-keys.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/input/keyboard/lpc32xx-keys.c b/drivers/input/keyboard/lpc32xx-keys.c index 911e1181cd6fb..322a878071591 100644 --- a/drivers/input/keyboard/lpc32xx-keys.c +++ b/drivers/input/keyboard/lpc32xx-keys.c @@ -160,17 +160,10 @@ static int lpc32xx_kscan_probe(struct platform_device *pdev) { struct lpc32xx_kscan_drv *kscandat; struct input_dev *input; - struct resource *res; size_t keymap_size; int error; int irq; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "failed to get platform I/O memory\n"); - return -EINVAL; - } - irq = platform_get_irq(pdev, 0); if (irq < 0) return -EINVAL; @@ -221,7 +214,7 @@ static int lpc32xx_kscan_probe(struct platform_device *pdev) input_set_drvdata(kscandat->input, kscandat); - kscandat->kscan_base = devm_ioremap_resource(&pdev->dev, res); + kscandat->kscan_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(kscandat->kscan_base)) return PTR_ERR(kscandat->kscan_base); -- GitLab From b1066df414d7ef6d9674c259b8871f428e12fd63 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 15:26:25 -0700 Subject: [PATCH 0062/3445] Input: nspire-keypad - use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230705052346.39337-3-frank.li@vivo.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/nspire-keypad.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/input/keyboard/nspire-keypad.c b/drivers/input/keyboard/nspire-keypad.c index e9fa1423f1360..096c18d7bca11 100644 --- a/drivers/input/keyboard/nspire-keypad.c +++ b/drivers/input/keyboard/nspire-keypad.c @@ -186,8 +186,7 @@ static int nspire_keypad_probe(struct platform_device *pdev) return PTR_ERR(keypad->clk); } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - keypad->reg_base = devm_ioremap_resource(&pdev->dev, res); + keypad->reg_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(keypad->reg_base)) return PTR_ERR(keypad->reg_base); -- GitLab From e79637731c6a386baa567f7210791b88216ec8bf Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 16:39:23 -0700 Subject: [PATCH 0063/3445] Input: omap4-keyad - convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230705052346.39337-4-frank.li@vivo.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/omap4-keypad.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index 9f085d5679dbb..773e55eed88b1 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -341,17 +341,10 @@ static int omap4_keypad_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct omap4_keypad *keypad_data; struct input_dev *input_dev; - struct resource *res; unsigned int max_keys; int irq; int error; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "no base address specified\n"); - return -EINVAL; - } - irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; @@ -370,7 +363,7 @@ static int omap4_keypad_probe(struct platform_device *pdev) if (error) return error; - keypad_data->base = devm_ioremap_resource(dev, res); + keypad_data->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(keypad_data->base)) return PTR_ERR(keypad_data->base); -- GitLab From db9842298ad525265d48aa6b9da20f37a4a36481 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 16:40:10 -0700 Subject: [PATCH 0064/3445] Input: opencores-kbd - convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230705052346.39337-5-frank.li@vivo.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/opencores-kbd.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/input/keyboard/opencores-kbd.c b/drivers/input/keyboard/opencores-kbd.c index b0ea387414c1e..7ffe1a70c8566 100644 --- a/drivers/input/keyboard/opencores-kbd.c +++ b/drivers/input/keyboard/opencores-kbd.c @@ -39,15 +39,8 @@ static int opencores_kbd_probe(struct platform_device *pdev) { struct input_dev *input; struct opencores_kbd *opencores_kbd; - struct resource *res; int irq, i, error; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "missing board memory resource\n"); - return -EINVAL; - } - irq = platform_get_irq(pdev, 0); if (irq < 0) return -EINVAL; @@ -65,7 +58,7 @@ static int opencores_kbd_probe(struct platform_device *pdev) opencores_kbd->input = input; - opencores_kbd->addr = devm_ioremap_resource(&pdev->dev, res); + opencores_kbd->addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(opencores_kbd->addr)) return PTR_ERR(opencores_kbd->addr); -- GitLab From 198a2ccaaab8fca64f7b367969038badae96f3bd Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 16:40:32 -0700 Subject: [PATCH 0065/3445] Input: pxa27x_keypad - convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230705052346.39337-6-frank.li@vivo.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/pxa27x_keypad.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index 871f858d0ba78..3724363d140e5 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -717,7 +717,6 @@ static int pxa27x_keypad_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct pxa27x_keypad *keypad; struct input_dev *input_dev; - struct resource *res; int irq, error; /* Driver need build keycode from device tree or pdata */ @@ -728,12 +727,6 @@ static int pxa27x_keypad_probe(struct platform_device *pdev) if (irq < 0) return -ENXIO; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "failed to get I/O memory\n"); - return -ENXIO; - } - keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad), GFP_KERNEL); if (!keypad) @@ -747,7 +740,7 @@ static int pxa27x_keypad_probe(struct platform_device *pdev) keypad->input_dev = input_dev; keypad->irq = irq; - keypad->mmio_base = devm_ioremap_resource(&pdev->dev, res); + keypad->mmio_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(keypad->mmio_base)) return PTR_ERR(keypad->mmio_base); -- GitLab From b1c5590045a08751f3d523b2343e848365e6b046 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 16:40:46 -0700 Subject: [PATCH 0066/3445] Input: sun4i-lradc-keys - convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230705052346.39337-7-frank.li@vivo.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/sun4i-lradc-keys.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/input/keyboard/sun4i-lradc-keys.c b/drivers/input/keyboard/sun4i-lradc-keys.c index 15c15c0958b00..95d927cc8b7e8 100644 --- a/drivers/input/keyboard/sun4i-lradc-keys.c +++ b/drivers/input/keyboard/sun4i-lradc-keys.c @@ -307,8 +307,7 @@ static int sun4i_lradc_probe(struct platform_device *pdev) input_set_drvdata(lradc->input, lradc); - lradc->base = devm_ioremap_resource(dev, - platform_get_resource(pdev, IORESOURCE_MEM, 0)); + lradc->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(lradc->base)) return PTR_ERR(lradc->base); -- GitLab From c0551abb0557bb25440d57b60fc11f8ed13d62e9 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 17:29:41 -0700 Subject: [PATCH 0067/3445] Input: nomadik-ske-keypad - convert to use devm_* api Use devm_* api to simplify code, this makes it unnecessary to explicitly release resources. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230705052346.39337-8-frank.li@vivo.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/nomadik-ske-keypad.c | 127 ++++++-------------- 1 file changed, 35 insertions(+), 92 deletions(-) diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c index 970f2a671c2e6..b3ccc97f61e1f 100644 --- a/drivers/input/keyboard/nomadik-ske-keypad.c +++ b/drivers/input/keyboard/nomadik-ske-keypad.c @@ -221,13 +221,20 @@ static irqreturn_t ske_keypad_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static void ske_keypad_board_exit(void *data) +{ + struct ske_keypad *keypad = data; + + keypad->board->exit(); +} + static int __init ske_keypad_probe(struct platform_device *pdev) { const struct ske_keypad_platform_data *plat = dev_get_platdata(&pdev->dev); + struct device *dev = &pdev->dev; struct ske_keypad *keypad; struct input_dev *input; - struct resource *res; int irq; int error; @@ -238,20 +245,14 @@ static int __init ske_keypad_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) - return -EINVAL; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "missing platform resources\n"); - return -EINVAL; - } + return irq; - keypad = kzalloc(sizeof(struct ske_keypad), GFP_KERNEL); - input = input_allocate_device(); + keypad = devm_kzalloc(dev, sizeof(struct ske_keypad), + GFP_KERNEL); + input = devm_input_allocate_device(dev); if (!keypad || !input) { dev_err(&pdev->dev, "failed to allocate keypad memory\n"); - error = -ENOMEM; - goto err_free_mem; + return -ENOMEM; } keypad->irq = irq; @@ -259,31 +260,20 @@ static int __init ske_keypad_probe(struct platform_device *pdev) keypad->input = input; spin_lock_init(&keypad->ske_keypad_lock); - if (!request_mem_region(res->start, resource_size(res), pdev->name)) { - dev_err(&pdev->dev, "failed to request I/O memory\n"); - error = -EBUSY; - goto err_free_mem; - } - - keypad->reg_base = ioremap(res->start, resource_size(res)); - if (!keypad->reg_base) { - dev_err(&pdev->dev, "failed to remap I/O memory\n"); - error = -ENXIO; - goto err_free_mem_region; - } + keypad->reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(keypad->reg_base)) + return PTR_ERR(keypad->reg_base); - keypad->pclk = clk_get(&pdev->dev, "apb_pclk"); + keypad->pclk = devm_clk_get_enabled(dev, "apb_pclk"); if (IS_ERR(keypad->pclk)) { dev_err(&pdev->dev, "failed to get pclk\n"); - error = PTR_ERR(keypad->pclk); - goto err_iounmap; + return PTR_ERR(keypad->pclk); } - keypad->clk = clk_get(&pdev->dev, NULL); + keypad->clk = devm_clk_get_enabled(dev, NULL); if (IS_ERR(keypad->clk)) { dev_err(&pdev->dev, "failed to get clk\n"); - error = PTR_ERR(keypad->clk); - goto err_pclk; + return PTR_ERR(keypad->clk); } input->id.bustype = BUS_HOST; @@ -295,48 +285,43 @@ static int __init ske_keypad_probe(struct platform_device *pdev) keypad->keymap, input); if (error) { dev_err(&pdev->dev, "Failed to build keymap\n"); - goto err_clk; + return error; } input_set_capability(input, EV_MSC, MSC_SCAN); if (!plat->no_autorepeat) __set_bit(EV_REP, input->evbit); - error = clk_prepare_enable(keypad->pclk); - if (error) { - dev_err(&pdev->dev, "Failed to prepare/enable pclk\n"); - goto err_clk; - } - - error = clk_prepare_enable(keypad->clk); - if (error) { - dev_err(&pdev->dev, "Failed to prepare/enable clk\n"); - goto err_pclk_disable; - } - - /* go through board initialization helpers */ if (keypad->board->init) keypad->board->init(); + if (keypad->board->exit) { + error = devm_add_action_or_reset(dev, ske_keypad_board_exit, + keypad); + if (error) + return error; + } + error = ske_keypad_chip_init(keypad); if (error) { dev_err(&pdev->dev, "unable to init keypad hardware\n"); - goto err_clk_disable; + return error; } - error = request_threaded_irq(keypad->irq, NULL, ske_keypad_irq, - IRQF_ONESHOT, "ske-keypad", keypad); + error = devm_request_threaded_irq(dev, keypad->irq, + NULL, ske_keypad_irq, + IRQF_ONESHOT, "ske-keypad", keypad); if (error) { dev_err(&pdev->dev, "allocate irq %d failed\n", keypad->irq); - goto err_clk_disable; + return error; } error = input_register_device(input); if (error) { dev_err(&pdev->dev, - "unable to register input device: %d\n", error); - goto err_free_irq; + "unable to register input device: %d\n", error); + return error; } if (plat->wakeup_enable) @@ -344,47 +329,6 @@ static int __init ske_keypad_probe(struct platform_device *pdev) platform_set_drvdata(pdev, keypad); - return 0; - -err_free_irq: - free_irq(keypad->irq, keypad); -err_clk_disable: - clk_disable_unprepare(keypad->clk); -err_pclk_disable: - clk_disable_unprepare(keypad->pclk); -err_clk: - clk_put(keypad->clk); -err_pclk: - clk_put(keypad->pclk); -err_iounmap: - iounmap(keypad->reg_base); -err_free_mem_region: - release_mem_region(res->start, resource_size(res)); -err_free_mem: - input_free_device(input); - kfree(keypad); - return error; -} - -static int ske_keypad_remove(struct platform_device *pdev) -{ - struct ske_keypad *keypad = platform_get_drvdata(pdev); - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - free_irq(keypad->irq, keypad); - - input_unregister_device(keypad->input); - - clk_disable_unprepare(keypad->clk); - clk_put(keypad->clk); - - if (keypad->board->exit) - keypad->board->exit(); - - iounmap(keypad->reg_base); - release_mem_region(res->start, resource_size(res)); - kfree(keypad); - return 0; } @@ -424,7 +368,6 @@ static struct platform_driver ske_keypad_driver = { .name = "nmk-ske-keypad", .pm = pm_sleep_ptr(&ske_keypad_dev_pm_ops), }, - .remove = ske_keypad_remove, }; module_platform_driver_probe(ske_keypad_driver, ske_keypad_probe); -- GitLab From f1efdf7fcef91fdeb2664b5856fdc51a049b8892 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 17:22:04 -0700 Subject: [PATCH 0068/3445] Input: lpc32xx_ts - convert to use devm_* api Use devm_* api to simplify code, this makes it unnecessary to explicitly release resources. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230705052346.39337-10-frank.li@vivo.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/lpc32xx_ts.c | 98 ++++++-------------------- 1 file changed, 22 insertions(+), 76 deletions(-) diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c index 15b5cb763526a..9bad8b93c0395 100644 --- a/drivers/input/touchscreen/lpc32xx_ts.c +++ b/drivers/input/touchscreen/lpc32xx_ts.c @@ -198,54 +198,36 @@ static void lpc32xx_ts_close(struct input_dev *dev) static int lpc32xx_ts_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct lpc32xx_tsc *tsc; struct input_dev *input; - struct resource *res; - resource_size_t size; int irq; int error; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Can't get memory resource\n"); - return -ENOENT; - } - irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; - tsc = kzalloc(sizeof(*tsc), GFP_KERNEL); - input = input_allocate_device(); - if (!tsc || !input) { - dev_err(&pdev->dev, "failed allocating memory\n"); - error = -ENOMEM; - goto err_free_mem; - } + tsc = devm_kzalloc(dev, sizeof(*tsc), GFP_KERNEL); + if (!tsc) + return -ENOMEM; - tsc->dev = input; tsc->irq = irq; - size = resource_size(res); - - if (!request_mem_region(res->start, size, pdev->name)) { - dev_err(&pdev->dev, "TSC registers are not free\n"); - error = -EBUSY; - goto err_free_mem; - } + tsc->tsc_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(tsc->tsc_base)) + return PTR_ERR(tsc->tsc_base); - tsc->tsc_base = ioremap(res->start, size); - if (!tsc->tsc_base) { - dev_err(&pdev->dev, "Can't map memory\n"); - error = -ENOMEM; - goto err_release_mem; - } - - tsc->clk = clk_get(&pdev->dev, NULL); + tsc->clk = devm_clk_get(dev, NULL); if (IS_ERR(tsc->clk)) { dev_err(&pdev->dev, "failed getting clock\n"); - error = PTR_ERR(tsc->clk); - goto err_unmap; + return PTR_ERR(tsc->clk); + } + + input = devm_input_allocate_device(dev); + if (!input) { + dev_err(&pdev->dev, "failed allocating input device\n"); + return -ENOMEM; } input->name = MOD_NAME; @@ -254,68 +236,33 @@ static int lpc32xx_ts_probe(struct platform_device *pdev) input->id.vendor = 0x0001; input->id.product = 0x0002; input->id.version = 0x0100; - input->dev.parent = &pdev->dev; input->open = lpc32xx_ts_open; input->close = lpc32xx_ts_close; - input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + input_set_capability(input, EV_KEY, BTN_TOUCH); input_set_abs_params(input, ABS_X, LPC32XX_TSC_MIN_XY_VAL, LPC32XX_TSC_MAX_XY_VAL, 0, 0); input_set_abs_params(input, ABS_Y, LPC32XX_TSC_MIN_XY_VAL, LPC32XX_TSC_MAX_XY_VAL, 0, 0); input_set_drvdata(input, tsc); + tsc->dev = input; - error = request_irq(tsc->irq, lpc32xx_ts_interrupt, - 0, pdev->name, tsc); + error = devm_request_irq(dev, tsc->irq, lpc32xx_ts_interrupt, + 0, pdev->name, tsc); if (error) { dev_err(&pdev->dev, "failed requesting interrupt\n"); - goto err_put_clock; + return error; } error = input_register_device(input); if (error) { dev_err(&pdev->dev, "failed registering input device\n"); - goto err_free_irq; + return error; } platform_set_drvdata(pdev, tsc); - device_init_wakeup(&pdev->dev, 1); - - return 0; - -err_free_irq: - free_irq(tsc->irq, tsc); -err_put_clock: - clk_put(tsc->clk); -err_unmap: - iounmap(tsc->tsc_base); -err_release_mem: - release_mem_region(res->start, size); -err_free_mem: - input_free_device(input); - kfree(tsc); - - return error; -} - -static int lpc32xx_ts_remove(struct platform_device *pdev) -{ - struct lpc32xx_tsc *tsc = platform_get_drvdata(pdev); - struct resource *res; - - free_irq(tsc->irq, tsc); - - input_unregister_device(tsc->dev); - - clk_put(tsc->clk); - - iounmap(tsc->tsc_base); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - - kfree(tsc); + device_init_wakeup(&pdev->dev, true); return 0; } @@ -384,7 +331,6 @@ MODULE_DEVICE_TABLE(of, lpc32xx_tsc_of_match); static struct platform_driver lpc32xx_ts_driver = { .probe = lpc32xx_ts_probe, - .remove = lpc32xx_ts_remove, .driver = { .name = MOD_NAME, .pm = LPC32XX_TS_PM_OPS, -- GitLab From ea55d5a2cf7c507a9ac03b41716bf1877edad153 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Mon, 10 Jul 2023 19:31:37 +0000 Subject: [PATCH 0069/3445] KVM: arm64: Delete pointless switch statement in kvm_reset_vcpu() The vCPU target hasn't mattered for quite a long time now. Delete the useless switch statement in kvm_reset_vcpu(), which hilariously only had a default case in it. Reviewed-by: Zenghui Yu Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20230710193140.1706399-2-oliver.upton@linux.dev --- arch/arm64/kvm/reset.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index bc8556b6f4590..7a65a35ee4ac4 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -248,21 +248,16 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu) } } - switch (vcpu->arch.target) { - default: - if (vcpu_el1_is_32bit(vcpu)) { - pstate = VCPU_RESET_PSTATE_SVC; - } else if (vcpu_has_nv(vcpu)) { - pstate = VCPU_RESET_PSTATE_EL2; - } else { - pstate = VCPU_RESET_PSTATE_EL1; - } - - if (kvm_vcpu_has_pmu(vcpu) && !kvm_arm_support_pmu_v3()) { - ret = -EINVAL; - goto out; - } - break; + if (vcpu_el1_is_32bit(vcpu)) + pstate = VCPU_RESET_PSTATE_SVC; + else if (vcpu_has_nv(vcpu)) + pstate = VCPU_RESET_PSTATE_EL2; + else + pstate = VCPU_RESET_PSTATE_EL1; + + if (kvm_vcpu_has_pmu(vcpu) && !kvm_arm_support_pmu_v3()) { + ret = -EINVAL; + goto out; } /* Reset core registers */ -- GitLab From c8a67729b8a36a5f4857de645ee9808fc99d8618 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Mon, 10 Jul 2023 19:31:38 +0000 Subject: [PATCH 0070/3445] KVM: arm64: Remove pointless check for changed init target At any time there is only a single valid value for KVM_ARM_VCPU_INIT, depending on the current CPU implementation. In all likelihood, this will be the generic ARMv8 target. Drop the pointless check for a changed target value between calls to KVM_ARM_VCPU_INIT and instead rely on the check against kvm_target_cpu(). Signed-off-by: Oliver Upton Reviewed-by: Zenghui Yu Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20230710193140.1706399-3-oliver.upton@linux.dev --- arch/arm64/kvm/arm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index c2c14059f6a8c..3f844934b9f35 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -1212,8 +1212,7 @@ static bool kvm_vcpu_init_changed(struct kvm_vcpu *vcpu, { unsigned long features = init->features[0]; - return !bitmap_equal(vcpu->arch.features, &features, KVM_VCPU_MAX_FEATURES) || - vcpu->arch.target != init->target; + return !bitmap_equal(vcpu->arch.features, &features, KVM_VCPU_MAX_FEATURES); } static int __kvm_vcpu_set_target(struct kvm_vcpu *vcpu, -- GitLab From ef98406036769107d5c49a519b31c940910b98d3 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Mon, 10 Jul 2023 19:31:39 +0000 Subject: [PATCH 0071/3445] KVM: arm64: Replace vCPU target with a configuration flag The value of kvm_vcpu_arch::target has been used to determine if a vCPU has actually been initialized. Storing this as an integer is needless at this point, as KVM doesn't do any microarch-specific emulation in the first place. Instead, all we care about is whether or not the vCPU has been initialized. Delete the field in favor of a vCPU configuration flag indicating if KVM_ARM_VCPU_INIT has completed for the vCPU. Reviewed-by: Zenghui Yu Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20230710193140.1706399-4-oliver.upton@linux.dev --- arch/arm64/include/asm/kvm_host.h | 5 +++-- arch/arm64/kvm/arm.c | 12 +++++------- arch/arm64/kvm/hyp/nvhe/switch.c | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 8b6096753740c..b53105bccff9a 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -567,8 +567,7 @@ struct kvm_vcpu_arch { /* Cache some mmu pages needed inside spinlock regions */ struct kvm_mmu_memory_cache mmu_page_cache; - /* Target CPU and feature flags */ - int target; + /* feature flags */ DECLARE_BITMAP(features, KVM_VCPU_MAX_FEATURES); /* Virtual SError ESR to restore when HCR_EL2.VSE is set */ @@ -669,6 +668,8 @@ struct kvm_vcpu_arch { #define VCPU_SVE_FINALIZED __vcpu_single_flag(cflags, BIT(1)) /* PTRAUTH exposed to guest */ #define GUEST_HAS_PTRAUTH __vcpu_single_flag(cflags, BIT(2)) +/* KVM_ARM_VCPU_INIT completed */ +#define VCPU_INITIALIZED __vcpu_single_flag(cflags, BIT(3)) /* Exception pending */ #define PENDING_EXCEPTION __vcpu_single_flag(iflags, BIT(0)) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 3f844934b9f35..13f1bde0bc2d7 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -360,7 +360,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) #endif /* Force users to call KVM_ARM_VCPU_INIT */ - vcpu->arch.target = -1; + vcpu_clear_flag(vcpu, VCPU_INITIALIZED); bitmap_zero(vcpu->arch.features, KVM_VCPU_MAX_FEATURES); vcpu->arch.mmu_page_cache.gfp_zero = __GFP_ZERO; @@ -569,7 +569,7 @@ unsigned long kvm_arch_vcpu_get_ip(struct kvm_vcpu *vcpu) static int kvm_vcpu_initialized(struct kvm_vcpu *vcpu) { - return vcpu->arch.target >= 0; + return vcpu_get_flag(vcpu, VCPU_INITIALIZED); } /* @@ -1051,7 +1051,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) * invalid. The VMM can try and fix it by issuing a * KVM_ARM_VCPU_INIT if it really wants to. */ - vcpu->arch.target = -1; + vcpu_clear_flag(vcpu, VCPU_INITIALIZED); ret = ARM_EXCEPTION_IL; } @@ -1228,20 +1228,18 @@ static int __kvm_vcpu_set_target(struct kvm_vcpu *vcpu, !bitmap_equal(kvm->arch.vcpu_features, &features, KVM_VCPU_MAX_FEATURES)) goto out_unlock; - vcpu->arch.target = init->target; bitmap_copy(vcpu->arch.features, &features, KVM_VCPU_MAX_FEATURES); /* Now we know what it is, we can reset it. */ ret = kvm_reset_vcpu(vcpu); if (ret) { - vcpu->arch.target = -1; bitmap_zero(vcpu->arch.features, KVM_VCPU_MAX_FEATURES); goto out_unlock; } bitmap_copy(kvm->arch.vcpu_features, &features, KVM_VCPU_MAX_FEATURES); set_bit(KVM_ARCH_FLAG_VCPU_FEATURES_CONFIGURED, &kvm->arch.flags); - + vcpu_set_flag(vcpu, VCPU_INITIALIZED); out_unlock: mutex_unlock(&kvm->arch.config_lock); return ret; @@ -1259,7 +1257,7 @@ static int kvm_vcpu_set_target(struct kvm_vcpu *vcpu, if (ret) return ret; - if (vcpu->arch.target == -1) + if (!kvm_vcpu_initialized(vcpu)) return __kvm_vcpu_set_target(vcpu, init); if (kvm_vcpu_init_changed(vcpu, init)) diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c index 0a6271052def0..b9caac3e7b1d0 100644 --- a/arch/arm64/kvm/hyp/nvhe/switch.c +++ b/arch/arm64/kvm/hyp/nvhe/switch.c @@ -236,7 +236,7 @@ static void early_exit_filter(struct kvm_vcpu *vcpu, u64 *exit_code) * KVM_ARM_VCPU_INIT, however, this is likely not possible for * protected VMs. */ - vcpu->arch.target = -1; + vcpu_clear_flag(vcpu, VCPU_INITIALIZED); *exit_code &= BIT(ARM_EXIT_WITH_SERROR_BIT); *exit_code |= ARM_EXCEPTION_IL; } -- GitLab From 5346f7e13e5eb134920a14504b6900c6168dd16e Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Mon, 10 Jul 2023 19:31:40 +0000 Subject: [PATCH 0072/3445] KVM: arm64: Always return generic v8 as the preferred target Userspace selecting an implementation-specific vCPU target has been completely useless for a very long time. Let's go whole hog and start returning the generic v8 target across all implementations as the preferred target. Uphold the pre-existing behavior by tolerating either the generic target or an implementation-specific target if the vCPU happens to be running on one of the lucky few parts. Acked-by: Zenghui Yu Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20230710193140.1706399-5-oliver.upton@linux.dev --- arch/arm64/include/asm/kvm_host.h | 1 - arch/arm64/kvm/arm.c | 9 +++++---- arch/arm64/kvm/guest.c | 15 --------------- 3 files changed, 5 insertions(+), 20 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index b53105bccff9a..ed60277e834ad 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -898,7 +898,6 @@ struct kvm_vcpu_stat { u64 exits; }; -void kvm_vcpu_preferred_target(struct kvm_vcpu_init *init); unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu); int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices); int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 13f1bde0bc2d7..9ab17ecd76bb5 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -1250,7 +1250,8 @@ static int kvm_vcpu_set_target(struct kvm_vcpu *vcpu, { int ret; - if (init->target != kvm_target_cpu()) + if (init->target != KVM_ARM_TARGET_GENERIC_V8 && + init->target != kvm_target_cpu()) return -EINVAL; ret = kvm_vcpu_init_check_features(vcpu, init); @@ -1585,9 +1586,9 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) return kvm_vm_ioctl_set_device_addr(kvm, &dev_addr); } case KVM_ARM_PREFERRED_TARGET: { - struct kvm_vcpu_init init; - - kvm_vcpu_preferred_target(&init); + struct kvm_vcpu_init init = { + .target = KVM_ARM_TARGET_GENERIC_V8, + }; if (copy_to_user(argp, &init, sizeof(init))) return -EFAULT; diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 20280a5233f67..95f6945c44325 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -884,21 +884,6 @@ u32 __attribute_const__ kvm_target_cpu(void) return KVM_ARM_TARGET_GENERIC_V8; } -void kvm_vcpu_preferred_target(struct kvm_vcpu_init *init) -{ - u32 target = kvm_target_cpu(); - - memset(init, 0, sizeof(*init)); - - /* - * For now, we don't return any features. - * In future, we might use features to return target - * specific features available for the preferred - * target type. - */ - init->target = (__u32)target; -} - int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) { return -EINVAL; -- GitLab From 30a5b62e1c83d7660c6c471915ad968b6c6b7d98 Mon Sep 17 00:00:00 2001 From: Maurizio Lombardi Date: Fri, 30 Jun 2023 17:53:09 +0200 Subject: [PATCH 0073/3445] scsi: target: iscsi: Remove the unused netif_timeout attribute This attribute has never been used, remove it. Signed-off-by: Maurizio Lombardi Link: https://lore.kernel.org/r/20230630155309.46061-1-mlombard@redhat.com Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_configfs.c | 2 -- drivers/target/iscsi/iscsi_target_tpg.c | 26 -------------------- drivers/target/iscsi/iscsi_target_tpg.h | 1 - include/target/iscsi/iscsi_target_core.h | 4 --- 4 files changed, 33 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 5d0f51822414e..6ce967f5af141 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -783,7 +783,6 @@ CONFIGFS_ATTR(iscsi_tpg_attrib_, name) DEF_TPG_ATTRIB(authentication); DEF_TPG_ATTRIB(login_timeout); -DEF_TPG_ATTRIB(netif_timeout); DEF_TPG_ATTRIB(generate_node_acls); DEF_TPG_ATTRIB(default_cmdsn_depth); DEF_TPG_ATTRIB(cache_dynamic_acls); @@ -799,7 +798,6 @@ DEF_TPG_ATTRIB(login_keys_workaround); static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = { &iscsi_tpg_attrib_attr_authentication, &iscsi_tpg_attrib_attr_login_timeout, - &iscsi_tpg_attrib_attr_netif_timeout, &iscsi_tpg_attrib_attr_generate_node_acls, &iscsi_tpg_attrib_attr_default_cmdsn_depth, &iscsi_tpg_attrib_attr_cache_dynamic_acls, diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 3cac1aafef689..f7bac98fd4fef 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -211,7 +211,6 @@ static void iscsit_set_default_tpg_attribs(struct iscsi_portal_group *tpg) a->authentication = TA_AUTHENTICATION; a->login_timeout = TA_LOGIN_TIMEOUT; - a->netif_timeout = TA_NETIF_TIMEOUT; a->default_cmdsn_depth = TA_DEFAULT_CMDSN_DEPTH; a->generate_node_acls = TA_GENERATE_NODE_ACLS; a->cache_dynamic_acls = TA_CACHE_DYNAMIC_ACLS; @@ -666,31 +665,6 @@ int iscsit_ta_login_timeout( return 0; } -int iscsit_ta_netif_timeout( - struct iscsi_portal_group *tpg, - u32 netif_timeout) -{ - struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; - - if (netif_timeout > TA_NETIF_TIMEOUT_MAX) { - pr_err("Requested Network Interface Timeout %u larger" - " than maximum %u\n", netif_timeout, - TA_NETIF_TIMEOUT_MAX); - return -EINVAL; - } else if (netif_timeout < TA_NETIF_TIMEOUT_MIN) { - pr_err("Requested Network Interface Timeout %u smaller" - " than minimum %u\n", netif_timeout, - TA_NETIF_TIMEOUT_MIN); - return -EINVAL; - } - - a->netif_timeout = netif_timeout; - pr_debug("Set Network Interface Timeout to %u for" - " Target Portal Group %hu\n", a->netif_timeout, tpg->tpgt); - - return 0; -} - int iscsit_ta_generate_node_acls( struct iscsi_portal_group *tpg, u32 flag) diff --git a/drivers/target/iscsi/iscsi_target_tpg.h b/drivers/target/iscsi/iscsi_target_tpg.h index 839e453627769..71d067f621778 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.h +++ b/drivers/target/iscsi/iscsi_target_tpg.h @@ -38,7 +38,6 @@ extern int iscsit_tpg_del_network_portal(struct iscsi_portal_group *, struct iscsi_tpg_np *); extern int iscsit_ta_authentication(struct iscsi_portal_group *, u32); extern int iscsit_ta_login_timeout(struct iscsi_portal_group *, u32); -extern int iscsit_ta_netif_timeout(struct iscsi_portal_group *, u32); extern int iscsit_ta_generate_node_acls(struct iscsi_portal_group *, u32); extern int iscsit_ta_default_cmdsn_depth(struct iscsi_portal_group *, u32); extern int iscsit_ta_cache_dynamic_acls(struct iscsi_portal_group *, u32); diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index 4c15420e8965d..60af7c63b34e6 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -50,9 +50,6 @@ struct sock; #define TA_LOGIN_TIMEOUT 15 #define TA_LOGIN_TIMEOUT_MAX 30 #define TA_LOGIN_TIMEOUT_MIN 5 -#define TA_NETIF_TIMEOUT 2 -#define TA_NETIF_TIMEOUT_MAX 15 -#define TA_NETIF_TIMEOUT_MIN 2 #define TA_GENERATE_NODE_ACLS 0 #define TA_DEFAULT_CMDSN_DEPTH 64 #define TA_DEFAULT_CMDSN_DEPTH_MAX 512 @@ -773,7 +770,6 @@ to_iscsi_nacl(struct se_node_acl *se_nacl) struct iscsi_tpg_attrib { u32 authentication; u32 login_timeout; - u32 netif_timeout; u32 generate_node_acls; u32 cache_dynamic_acls; u32 default_cmdsn_depth; -- GitLab From aa2db9d44a8b9b3cb12df7c253b3d6f46618d37e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 6 Jul 2023 14:50:24 -0700 Subject: [PATCH 0074/3445] scsi: ufs: core: Convert UPIU_HEADER_DWORD() into a function This change reduces the number of parentheses that are required in the definition of this function and also when using this function. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20230706215054.4113469-1-bvanassche@acm.org Reviewed-by: Avri Altman Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 13 ++++++------- drivers/ufs/core/ufshpb.c | 2 +- include/ufs/ufs.h | 8 +++++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 983fae84d9e80..f00375daaf99f 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -2637,10 +2637,10 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u8 upiu_flags) unsigned short cdb_len; /* command descriptor fields */ - ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD( + ucd_req_ptr->header.dword_0 = upiu_header_dword( UPIU_TRANSACTION_COMMAND, upiu_flags, lrbp->lun, lrbp->task_tag); - ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD( + ucd_req_ptr->header.dword_1 = upiu_header_dword( UPIU_COMMAND_SET_TYPE_SCSI, 0, 0, 0); /* Total EHS length and Data segment length will be zero */ @@ -2669,16 +2669,16 @@ static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, u16 len = be16_to_cpu(query->request.upiu_req.length); /* Query request header */ - ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD( + ucd_req_ptr->header.dword_0 = upiu_header_dword( UPIU_TRANSACTION_QUERY_REQ, upiu_flags, lrbp->lun, lrbp->task_tag); - ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD( + ucd_req_ptr->header.dword_1 = upiu_header_dword( 0, query->request.query_func, 0, 0); /* Data segment length only need for WRITE_DESC */ if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) ucd_req_ptr->header.dword_2 = - UPIU_HEADER_DWORD(0, 0, (len >> 8), (u8)len); + upiu_header_dword(0, 0, len >> 8, (u8)len); else ucd_req_ptr->header.dword_2 = 0; @@ -2700,8 +2700,7 @@ static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp) memset(ucd_req_ptr, 0, sizeof(struct utp_upiu_req)); /* command descriptor fields */ - ucd_req_ptr->header.dword_0 = - UPIU_HEADER_DWORD( + ucd_req_ptr->header.dword_0 = upiu_header_dword( UPIU_TRANSACTION_NOP_OUT, 0, 0, lrbp->task_tag); /* clear rest of the fields of basic header */ ucd_req_ptr->header.dword_1 = 0; diff --git a/drivers/ufs/core/ufshpb.c b/drivers/ufs/core/ufshpb.c index 255f8b38d0c2d..92398db10e33c 100644 --- a/drivers/ufs/core/ufshpb.c +++ b/drivers/ufs/core/ufshpb.c @@ -121,7 +121,7 @@ static bool ufshpb_is_hpb_rsp_valid(struct ufs_hba *hba, { /* Check HPB_UPDATE_ALERT */ if (!(lrbp->ucd_rsp_ptr->header.dword_2 & - UPIU_HEADER_DWORD(0, 2, 0, 0))) + upiu_header_dword(0, 2, 0, 0))) return false; if (be16_to_cpu(rsp_field->sense_data_len) != DEV_SENSE_SEG_LEN || diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h index 4e8d6240e589b..a2bc025a748e9 100644 --- a/include/ufs/ufs.h +++ b/include/ufs/ufs.h @@ -23,9 +23,11 @@ (sizeof(struct utp_upiu_header))) #define UFS_SENSE_SIZE 18 -#define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\ - cpu_to_be32((byte3 << 24) | (byte2 << 16) |\ - (byte1 << 8) | (byte0)) +static inline __be32 upiu_header_dword(u8 byte3, u8 byte2, u8 byte1, u8 byte0) +{ + return cpu_to_be32(byte3 << 24 | byte2 << 16 | byte1 << 8 | byte0); +} + /* * UFS device may have standard LUs and LUN id could be from 0x00 to * 0x7F. Standard LUs use "Peripheral Device Addressing Format". -- GitLab From 11afb65c100ac5b16dd8ea6c8fcd55a1c61c3886 Mon Sep 17 00:00:00 2001 From: Po-Wen Kao Date: Sat, 1 Jul 2023 20:44:40 +0800 Subject: [PATCH 0075/3445] scsi: ufs: core: Export symbols for MTK driver module Export symbols for MediaTek UFS driver's PM flow and IRQ handler. Signed-off-by: Po-Wen Kao Link: https://lore.kernel.org/r/20230701124442.10489-2-powen.kao@mediatek.com Reviewed-by: Bart Van Assche Reviewed-by: Stanley Chu Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-mcq.c | 3 +++ include/ufs/ufshcd.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index 6fb0e007af636..e8bad5e9518e3 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -97,6 +97,7 @@ void ufshcd_mcq_config_mac(struct ufs_hba *hba, u32 max_active_cmds) val |= FIELD_PREP(MCQ_CFG_MAC_MASK, max_active_cmds); ufshcd_writel(hba, val, REG_UFS_MCQ_CFG); } +EXPORT_SYMBOL_GPL(ufshcd_mcq_config_mac); /** * ufshcd_mcq_req_to_hwq - find the hardware queue on which the @@ -245,6 +246,7 @@ u32 ufshcd_mcq_read_cqis(struct ufs_hba *hba, int i) { return readl(mcq_opr_base(hba, OPR_CQIS, i) + REG_CQIS); } +EXPORT_SYMBOL_GPL(ufshcd_mcq_read_cqis); void ufshcd_mcq_write_cqis(struct ufs_hba *hba, u32 val, int i) { @@ -388,6 +390,7 @@ void ufshcd_mcq_make_queues_operational(struct ufs_hba *hba) MCQ_CFG_n(REG_SQATTR, i)); } } +EXPORT_SYMBOL_GPL(ufshcd_mcq_make_queues_operational); void ufshcd_mcq_enable_esi(struct ufs_hba *hba) { diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 6dc11fa0ebb10..9f579640b9094 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -1254,9 +1254,12 @@ void ufshcd_parse_dev_ref_clk_freq(struct ufs_hba *hba, struct clk *refclk); void ufshcd_update_evt_hist(struct ufs_hba *hba, u32 id, u32 val); void ufshcd_hba_stop(struct ufs_hba *hba); void ufshcd_schedule_eh_work(struct ufs_hba *hba); +void ufshcd_mcq_config_mac(struct ufs_hba *hba, u32 max_active_cmds); +u32 ufshcd_mcq_read_cqis(struct ufs_hba *hba, int i); void ufshcd_mcq_write_cqis(struct ufs_hba *hba, u32 val, int i); unsigned long ufshcd_mcq_poll_cqe_lock(struct ufs_hba *hba, struct ufs_hw_queue *hwq); +void ufshcd_mcq_make_queues_operational(struct ufs_hba *hba); void ufshcd_mcq_enable_esi(struct ufs_hba *hba); void ufshcd_mcq_config_esi(struct ufs_hba *hba, struct msi_msg *msg); -- GitLab From e152a616c88653e67244595979fde24038d9653a Mon Sep 17 00:00:00 2001 From: Po-Wen Kao Date: Sat, 1 Jul 2023 20:44:41 +0800 Subject: [PATCH 0076/3445] scsi: ufs: ufs-mediatek: Add MCQ support for MTK platform Add UFS MCQ vops and IRQ handler for MediaTek platform. PM flow is fixed accordingly. Signed-off-by: Po-Wen Kao Link: https://lore.kernel.org/r/20230701124442.10489-3-powen.kao@mediatek.com Suggested-by: AngeloGioacchino Del Regno Reviewed-by: Stanley Chu Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 174 +++++++++++++++++++++++++++++++- drivers/ufs/host/ufs-mediatek.h | 33 ++++++ 2 files changed, 205 insertions(+), 2 deletions(-) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index e68b05976f9eb..786b1469eb52c 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -27,8 +27,14 @@ #include #include "ufs-mediatek.h" +static int ufs_mtk_config_mcq(struct ufs_hba *hba, bool irq); + #define CREATE_TRACE_POINTS #include "ufs-mediatek-trace.h" +#undef CREATE_TRACE_POINTS + +#define MAX_SUPP_MAC 64 +#define MCQ_QUEUE_OFFSET(c) ((((c) >> 16) & 0xFF) * 0x200) static const struct ufs_dev_quirk ufs_mtk_dev_fixups[] = { { .wmanufacturerid = UFS_ANY_VENDOR, @@ -840,6 +846,38 @@ static void ufs_mtk_vreg_fix_vccqx(struct ufs_hba *hba) } } +static void ufs_mtk_init_mcq_irq(struct ufs_hba *hba) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + struct platform_device *pdev; + int i; + int irq; + + host->mcq_nr_intr = UFSHCD_MAX_Q_NR; + pdev = container_of(hba->dev, struct platform_device, dev); + + for (i = 0; i < host->mcq_nr_intr; i++) { + /* irq index 0 is legacy irq, sq/cq irq start from index 1 */ + irq = platform_get_irq(pdev, i + 1); + if (irq < 0) { + host->mcq_intr_info[i].irq = MTK_MCQ_INVALID_IRQ; + dev_err(hba->dev, "get platform mcq irq fail: %d\n", i); + goto failed; + } + host->mcq_intr_info[i].hba = hba; + host->mcq_intr_info[i].irq = irq; + dev_info(hba->dev, "get platform mcq irq: %d, %d\n", i, irq); + } + + return; +failed: + /* invalidate irq info */ + for (i = 0; i < host->mcq_nr_intr; i++) + host->mcq_intr_info[i].irq = MTK_MCQ_INVALID_IRQ; + + host->mcq_nr_intr = 0; +} + /** * ufs_mtk_init - find other essential mmio bases * @hba: host controller instance @@ -876,6 +914,8 @@ static int ufs_mtk_init(struct ufs_hba *hba) /* Initialize host capability */ ufs_mtk_init_host_caps(hba); + ufs_mtk_init_mcq_irq(hba); + err = ufs_mtk_bind_mphy(hba); if (err) goto out_variant_clear; @@ -1173,7 +1213,17 @@ static int ufs_mtk_link_set_hpm(struct ufs_hba *hba) else return err; - err = ufshcd_make_hba_operational(hba); + if (!hba->mcq_enabled) { + err = ufshcd_make_hba_operational(hba); + } else { + ufs_mtk_config_mcq(hba, false); + ufshcd_mcq_make_queues_operational(hba); + ufshcd_mcq_config_mac(hba, hba->nutrs); + /* Enable MCQ mode */ + ufshcd_writel(hba, ufshcd_readl(hba, REG_UFS_MEM_CFG) | 0x1, + REG_UFS_MEM_CFG); + } + if (err) return err; @@ -1497,6 +1547,121 @@ static int ufs_mtk_clk_scale_notify(struct ufs_hba *hba, bool scale_up, return 0; } +static int ufs_mtk_get_hba_mac(struct ufs_hba *hba) +{ + return MAX_SUPP_MAC; +} + +static int ufs_mtk_op_runtime_config(struct ufs_hba *hba) +{ + struct ufshcd_mcq_opr_info_t *opr; + int i; + + hba->mcq_opr[OPR_SQD].offset = REG_UFS_MTK_SQD; + hba->mcq_opr[OPR_SQIS].offset = REG_UFS_MTK_SQIS; + hba->mcq_opr[OPR_CQD].offset = REG_UFS_MTK_CQD; + hba->mcq_opr[OPR_CQIS].offset = REG_UFS_MTK_CQIS; + + for (i = 0; i < OPR_MAX; i++) { + opr = &hba->mcq_opr[i]; + opr->stride = REG_UFS_MCQ_STRIDE; + opr->base = hba->mmio_base + opr->offset; + } + + return 0; +} + +static int ufs_mtk_mcq_config_resource(struct ufs_hba *hba) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + + /* fail mcq initialization if interrupt is not filled properly */ + if (!host->mcq_nr_intr) { + dev_info(hba->dev, "IRQs not ready. MCQ disabled."); + return -EINVAL; + } + + hba->mcq_base = hba->mmio_base + MCQ_QUEUE_OFFSET(hba->mcq_capabilities); + return 0; +} + +static irqreturn_t ufs_mtk_mcq_intr(int irq, void *__intr_info) +{ + struct ufs_mtk_mcq_intr_info *mcq_intr_info = __intr_info; + struct ufs_hba *hba = mcq_intr_info->hba; + struct ufs_hw_queue *hwq; + u32 events; + int qid = mcq_intr_info->qid; + + hwq = &hba->uhq[qid]; + + events = ufshcd_mcq_read_cqis(hba, qid); + if (events) + ufshcd_mcq_write_cqis(hba, events, qid); + + if (events & UFSHCD_MCQ_CQIS_TAIL_ENT_PUSH_STS) + ufshcd_mcq_poll_cqe_lock(hba, hwq); + + return IRQ_HANDLED; +} + +static int ufs_mtk_config_mcq_irq(struct ufs_hba *hba) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + u32 irq, i; + int ret; + + for (i = 0; i < host->mcq_nr_intr; i++) { + irq = host->mcq_intr_info[i].irq; + if (irq == MTK_MCQ_INVALID_IRQ) { + dev_err(hba->dev, "invalid irq. %d\n", i); + return -ENOPARAM; + } + + host->mcq_intr_info[i].qid = i; + ret = devm_request_irq(hba->dev, irq, ufs_mtk_mcq_intr, 0, UFSHCD, + &host->mcq_intr_info[i]); + + dev_dbg(hba->dev, "request irq %d intr %s\n", irq, ret ? "failed" : ""); + + if (ret) { + dev_err(hba->dev, "Cannot request irq %d\n", ret); + return ret; + } + } + + return 0; +} + +static int ufs_mtk_config_mcq(struct ufs_hba *hba, bool irq) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + int ret = 0; + + if (!host->mcq_set_intr) { + /* Disable irq option register */ + ufshcd_rmwl(hba, MCQ_INTR_EN_MSK, 0, REG_UFS_MMIO_OPT_CTRL_0); + + if (irq) { + ret = ufs_mtk_config_mcq_irq(hba); + if (ret) + return ret; + } + + host->mcq_set_intr = true; + } + + ufshcd_rmwl(hba, MCQ_AH8, MCQ_AH8, REG_UFS_MMIO_OPT_CTRL_0); + ufshcd_rmwl(hba, MCQ_INTR_EN_MSK, MCQ_MULTI_INTR_EN, REG_UFS_MMIO_OPT_CTRL_0); + + return 0; +} + +static int ufs_mtk_config_esi(struct ufs_hba *hba) +{ + return ufs_mtk_config_mcq(hba, true); +} + /* * struct ufs_hba_mtk_vops - UFS MTK specific variant operations * @@ -1520,6 +1685,11 @@ static const struct ufs_hba_variant_ops ufs_hba_mtk_vops = { .event_notify = ufs_mtk_event_notify, .config_scaling_param = ufs_mtk_config_scaling_param, .clk_scale_notify = ufs_mtk_clk_scale_notify, + /* mcq vops */ + .get_hba_mac = ufs_mtk_get_hba_mac, + .op_runtime_config = ufs_mtk_op_runtime_config, + .mcq_config_resource = ufs_mtk_mcq_config_resource, + .config_esi = ufs_mtk_config_esi, }; /** @@ -1566,7 +1736,7 @@ skip_reset: out: if (err) - dev_info(dev, "probe failed %d\n", err); + dev_err(dev, "probe failed %d\n", err); of_node_put(reset_node); return err; diff --git a/drivers/ufs/host/ufs-mediatek.h b/drivers/ufs/host/ufs-mediatek.h index 2fc6d7b87694e..f76e80d91729c 100644 --- a/drivers/ufs/host/ufs-mediatek.h +++ b/drivers/ufs/host/ufs-mediatek.h @@ -10,11 +10,27 @@ #include #include +/* + * MCQ define and struct + */ +#define UFSHCD_MAX_Q_NR 8 +#define MTK_MCQ_INVALID_IRQ 0xFFFF + +/* REG_UFS_MMIO_OPT_CTRL_0 160h */ +#define EHS_EN BIT(0) +#define PFM_IMPV BIT(1) +#define MCQ_MULTI_INTR_EN BIT(2) +#define MCQ_CMB_INTR_EN BIT(3) +#define MCQ_AH8 BIT(4) + +#define MCQ_INTR_EN_MSK (MCQ_MULTI_INTR_EN | MCQ_CMB_INTR_EN) + /* * Vendor specific UFSHCI Registers */ #define REG_UFS_XOUFS_CTRL 0x140 #define REG_UFS_REFCLK_CTRL 0x144 +#define REG_UFS_MMIO_OPT_CTRL_0 0x160 #define REG_UFS_EXTREG 0x2100 #define REG_UFS_MPHYCTRL 0x2200 #define REG_UFS_MTK_IP_VER 0x2240 @@ -26,6 +42,13 @@ #define REG_UFS_DEBUG_SEL_B2 0x22D8 #define REG_UFS_DEBUG_SEL_B3 0x22DC +#define REG_UFS_MTK_SQD 0x2800 +#define REG_UFS_MTK_SQIS 0x2814 +#define REG_UFS_MTK_CQD 0x281C +#define REG_UFS_MTK_CQIS 0x2824 + +#define REG_UFS_MCQ_STRIDE 0x30 + /* * Ref-clk control * @@ -136,6 +159,12 @@ struct ufs_mtk_hw_ver { u8 major; }; +struct ufs_mtk_mcq_intr_info { + struct ufs_hba *hba; + u32 irq; + u8 qid; +}; + struct ufs_mtk_host { struct phy *mphy; struct pm_qos_request pm_qos_req; @@ -155,6 +184,10 @@ struct ufs_mtk_host { u16 ref_clk_ungating_wait_us; u16 ref_clk_gating_wait_us; u32 ip_ver; + + bool mcq_set_intr; + int mcq_nr_intr; + struct ufs_mtk_mcq_intr_info mcq_intr_info[UFSHCD_MAX_Q_NR]; }; /* -- GitLab From d1d4ff5d11a5887a9c4cfc00294bc68ba03e7c16 Mon Sep 17 00:00:00 2001 From: Miaohe Lin Date: Tue, 11 Jul 2023 10:38:20 +0800 Subject: [PATCH 0077/3445] cgroup: put cgroup_tryget_css() inside CONFIG_CGROUP_SCHED Put cgroup_tryget_css() inside CONFIG_CGROUP_SCHED to fix the warning of 'cgroup_tryget_css' defined but not used [-Wunused-function] when CONFIG_CGROUP_SCHED is disabled. Signed-off-by: Miaohe Lin Reviewed-by: Kamalesh Babulal Signed-off-by: Tejun Heo --- kernel/cgroup/cgroup.c | 44 +++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 13d9ea33eb6d5..30c9c2503ccf1 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -492,28 +492,6 @@ static struct cgroup_subsys_state *cgroup_css(struct cgroup *cgrp, return &cgrp->self; } -/** - * cgroup_tryget_css - try to get a cgroup's css for the specified subsystem - * @cgrp: the cgroup of interest - * @ss: the subsystem of interest - * - * Find and get @cgrp's css associated with @ss. If the css doesn't exist - * or is offline, %NULL is returned. - */ -static struct cgroup_subsys_state *cgroup_tryget_css(struct cgroup *cgrp, - struct cgroup_subsys *ss) -{ - struct cgroup_subsys_state *css; - - rcu_read_lock(); - css = cgroup_css(cgrp, ss); - if (css && !css_tryget_online(css)) - css = NULL; - rcu_read_unlock(); - - return css; -} - /** * cgroup_e_css_by_mask - obtain a cgroup's effective css for the specified ss * @cgrp: the cgroup of interest @@ -3655,6 +3633,28 @@ static int cgroup_stat_show(struct seq_file *seq, void *v) } #ifdef CONFIG_CGROUP_SCHED +/** + * cgroup_tryget_css - try to get a cgroup's css for the specified subsystem + * @cgrp: the cgroup of interest + * @ss: the subsystem of interest + * + * Find and get @cgrp's css associated with @ss. If the css doesn't exist + * or is offline, %NULL is returned. + */ +static struct cgroup_subsys_state *cgroup_tryget_css(struct cgroup *cgrp, + struct cgroup_subsys *ss) +{ + struct cgroup_subsys_state *css; + + rcu_read_lock(); + css = cgroup_css(cgrp, ss); + if (css && !css_tryget_online(css)) + css = NULL; + rcu_read_unlock(); + + return css; +} + static int cgroup_extra_stat_show(struct seq_file *seq, int ssid) { struct cgroup *cgrp = seq_css(seq)->cgroup; -- GitLab From 19bfa9ebebb5ec0695def57eb1d80de7e9cab369 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 20 Jun 2023 16:19:04 +0300 Subject: [PATCH 0078/3445] mtd: use refcount to prevent corruption When underlying device is removed mtd core will crash in case user space is holding open handle. Need to use proper refcounting so device is release only when has no users. Signed-off-by: Tomas Winkler Signed-off-by: Alexander Usyskin Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230620131905.648089-2-alexander.usyskin@intel.com --- drivers/mtd/mtdcore.c | 72 ++++++++++++++++++++++------------------- drivers/mtd/mtdcore.h | 1 + drivers/mtd/mtdpart.c | 14 ++++---- include/linux/mtd/mtd.h | 2 +- 4 files changed, 49 insertions(+), 40 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index e00b12aa5ec91..6dbd596a11293 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -93,10 +93,33 @@ static void mtd_release(struct device *dev) struct mtd_info *mtd = dev_get_drvdata(dev); dev_t index = MTD_DEVT(mtd->index); + if (mtd_is_partition(mtd)) + release_mtd_partition(mtd); + /* remove /dev/mtdXro node */ device_destroy(&mtd_class, index + 1); } +static void mtd_device_release(struct kref *kref) +{ + struct mtd_info *mtd = container_of(kref, struct mtd_info, refcnt); + + debugfs_remove_recursive(mtd->dbg.dfs_dir); + + /* Try to remove the NVMEM provider */ + nvmem_unregister(mtd->nvmem); + + device_unregister(&mtd->dev); + + /* Clear dev so mtd can be safely re-registered later if desired */ + memset(&mtd->dev, 0, sizeof(mtd->dev)); + + idr_remove(&mtd_idr, mtd->index); + of_node_put(mtd_get_of_node(mtd)); + + module_put(THIS_MODULE); +} + #define MTD_DEVICE_ATTR_RO(name) \ static DEVICE_ATTR(name, 0444, mtd_##name##_show, NULL) @@ -666,7 +689,7 @@ int add_mtd_device(struct mtd_info *mtd) } mtd->index = i; - mtd->usecount = 0; + kref_init(&mtd->refcnt); /* default value if not set by driver */ if (mtd->bitflip_threshold == 0) @@ -779,7 +802,6 @@ int del_mtd_device(struct mtd_info *mtd) { int ret; struct mtd_notifier *not; - struct device_node *mtd_of_node; mutex_lock(&mtd_table_mutex); @@ -793,28 +815,8 @@ int del_mtd_device(struct mtd_info *mtd) list_for_each_entry(not, &mtd_notifiers, list) not->remove(mtd); - if (mtd->usecount) { - printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n", - mtd->index, mtd->name, mtd->usecount); - ret = -EBUSY; - } else { - mtd_of_node = mtd_get_of_node(mtd); - debugfs_remove_recursive(mtd->dbg.dfs_dir); - - /* Try to remove the NVMEM provider */ - nvmem_unregister(mtd->nvmem); - - device_unregister(&mtd->dev); - - /* Clear dev so mtd can be safely re-registered later if desired */ - memset(&mtd->dev, 0, sizeof(mtd->dev)); - - idr_remove(&mtd_idr, mtd->index); - of_node_put(mtd_of_node); - - module_put(THIS_MODULE); - ret = 0; - } + kref_put(&mtd->refcnt, mtd_device_release); + ret = 0; out_error: mutex_unlock(&mtd_table_mutex); @@ -1230,19 +1232,21 @@ int __get_mtd_device(struct mtd_info *mtd) if (!try_module_get(master->owner)) return -ENODEV; + kref_get(&mtd->refcnt); + if (master->_get_device) { err = master->_get_device(mtd); if (err) { + kref_put(&mtd->refcnt, mtd_device_release); module_put(master->owner); return err; } } - master->usecount++; - while (mtd->parent) { - mtd->usecount++; + if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) || mtd->parent != master) + kref_get(&mtd->parent->refcnt); mtd = mtd->parent; } @@ -1329,18 +1333,20 @@ void __put_mtd_device(struct mtd_info *mtd) { struct mtd_info *master = mtd_get_master(mtd); - while (mtd->parent) { - --mtd->usecount; - BUG_ON(mtd->usecount < 0); - mtd = mtd->parent; - } + while (mtd != master) { + struct mtd_info *parent = mtd->parent; - master->usecount--; + kref_put(&mtd->refcnt, mtd_device_release); + mtd = parent; + } if (master->_put_device) master->_put_device(master); module_put(master->owner); + + if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) + kref_put(&master->refcnt, mtd_device_release); } EXPORT_SYMBOL_GPL(__put_mtd_device); diff --git a/drivers/mtd/mtdcore.h b/drivers/mtd/mtdcore.h index b5eefeabf310d..b014861a06a6f 100644 --- a/drivers/mtd/mtdcore.h +++ b/drivers/mtd/mtdcore.h @@ -12,6 +12,7 @@ int __must_check add_mtd_device(struct mtd_info *mtd); int del_mtd_device(struct mtd_info *mtd); int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int); int del_mtd_partitions(struct mtd_info *); +void release_mtd_partition(struct mtd_info *mtd); struct mtd_partitions; diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index a46affbb037d2..23483db8f30c9 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -32,6 +32,12 @@ static inline void free_partition(struct mtd_info *mtd) kfree(mtd); } +void release_mtd_partition(struct mtd_info *mtd) +{ + WARN_ON(!list_empty(&mtd->part.node)); + free_partition(mtd); +} + static struct mtd_info *allocate_partition(struct mtd_info *parent, const struct mtd_partition *part, int partno, uint64_t cur_offset) @@ -309,13 +315,11 @@ static int __mtd_del_partition(struct mtd_info *mtd) sysfs_remove_files(&mtd->dev.kobj, mtd_partition_attrs); + list_del_init(&mtd->part.node); err = del_mtd_device(mtd); if (err) return err; - list_del(&mtd->part.node); - free_partition(mtd); - return 0; } @@ -333,6 +337,7 @@ static int __del_mtd_partitions(struct mtd_info *mtd) __del_mtd_partitions(child); pr_info("Deleting %s MTD partition\n", child->name); + list_del_init(&child->part.node); ret = del_mtd_device(child); if (ret < 0) { pr_err("Error when deleting partition \"%s\" (%d)\n", @@ -340,9 +345,6 @@ static int __del_mtd_partitions(struct mtd_info *mtd) err = ret; continue; } - - list_del(&child->part.node); - free_partition(child); } return err; diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 7c58c44662b87..914a9f974baaa 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -379,7 +379,7 @@ struct mtd_info { struct module *owner; struct device dev; - int usecount; + struct kref refcnt; struct mtd_debug_info dbg; struct nvmem_device *nvmem; struct nvmem_device *otp_user_nvmem; -- GitLab From 79c4a56250216991f1d965ee26dcd273376e4e91 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Tue, 20 Jun 2023 16:19:05 +0300 Subject: [PATCH 0079/3445] mtd: call external _get and _put in right order MTD provider provides mtd_info object to mtd subsystem. With kref patch the mtd_info object can be alive after provider released mtd device. Fix calling order in _get and _put functions to allow mtd provider to safely alloc and release mtd object. Execute: 1) call external _get 2) get_module 3) add internal kref in the get function and opposite order in the put one. The _put_device callback should be the last in put as the master struct memory may be freed in this callback. Signed-off-by: Alexander Usyskin Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230620131905.648089-3-alexander.usyskin@intel.com --- drivers/mtd/mtdcore.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 6dbd596a11293..2466ea4664668 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -1229,21 +1229,20 @@ int __get_mtd_device(struct mtd_info *mtd) struct mtd_info *master = mtd_get_master(mtd); int err; - if (!try_module_get(master->owner)) - return -ENODEV; - - kref_get(&mtd->refcnt); - if (master->_get_device) { err = master->_get_device(mtd); - - if (err) { - kref_put(&mtd->refcnt, mtd_device_release); - module_put(master->owner); + if (err) return err; - } } + if (!try_module_get(master->owner)) { + if (master->_put_device) + master->_put_device(master); + return -ENODEV; + } + + kref_get(&mtd->refcnt); + while (mtd->parent) { if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) || mtd->parent != master) kref_get(&mtd->parent->refcnt); @@ -1340,13 +1339,14 @@ void __put_mtd_device(struct mtd_info *mtd) mtd = parent; } - if (master->_put_device) - master->_put_device(master); + if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) + kref_put(&master->refcnt, mtd_device_release); module_put(master->owner); - if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) - kref_put(&master->refcnt, mtd_device_release); + /* must be the last as master can be freed in the _put_device */ + if (master->_put_device) + master->_put_device(master); } EXPORT_SYMBOL_GPL(__put_mtd_device); -- GitLab From 746b0f2675de6cc2197a9363873de7274c539d84 Mon Sep 17 00:00:00 2001 From: Sridharan S N Date: Fri, 23 Jun 2023 10:27:55 +0530 Subject: [PATCH 0080/3445] mtd: spinand: gigadevice: add support for GD5F1GQ{4,5}RExxH Add support for: GD5F1GQ5RExxH GD5F1GQ4RExxH Both are 1Gb SLC NAND flash with 4b/512b on-die ECC capability and has 2K + 64B PageSize. Signed-off-by: Sridharan S N Signed-off-by: Md Sadre Alam Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230623045757.30055-2-quic_sridsn@quicinc.com --- drivers/mtd/nand/spi/gigadevice.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c index cfd7c3b26dc45..987710e09441a 100644 --- a/drivers/mtd/nand/spi/gigadevice.c +++ b/drivers/mtd/nand/spi/gigadevice.c @@ -511,6 +511,26 @@ static const struct spinand_info gigadevice_spinand_table[] = { SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, gd5fxgq4uexxg_ecc_get_status)), + SPINAND_INFO("GD5F1GQ5RExxH", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x21), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(4, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq4uexxg_ecc_get_status)), + SPINAND_INFO("GD5F1GQ4RExxH", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xc9), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(4, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq4uexxg_ecc_get_status)), }; static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = { -- GitLab From aa08bf187f322b6e38810d93896d052ea7cd6758 Mon Sep 17 00:00:00 2001 From: Sridharan S N Date: Fri, 23 Jun 2023 10:27:56 +0530 Subject: [PATCH 0081/3445] mtd: spinand: esmt: add support for F50D2G41KA This adds support for ESMT F50D2G41KA. This is 2Gb SLC NAND flash with 8b/512b on-die ECC capability. Signed-off-by: Sridharan S N Signed-off-by: Md Sadre Alam Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230623045757.30055-3-quic_sridsn@quicinc.com --- drivers/mtd/nand/spi/esmt.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/mtd/nand/spi/esmt.c b/drivers/mtd/nand/spi/esmt.c index 1a3ffb9823358..31c439a557b18 100644 --- a/drivers/mtd/nand/spi/esmt.c +++ b/drivers/mtd/nand/spi/esmt.c @@ -121,6 +121,15 @@ static const struct spinand_info esmt_c8_spinand_table[] = { &update_cache_variants), 0, SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)), + SPINAND_INFO("F50D2G41KA", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x51), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)), }; static const struct spinand_manufacturer_ops esmt_spinand_manuf_ops = { -- GitLab From dabd64be75ae38be09c35ea66037d410c68bc322 Mon Sep 17 00:00:00 2001 From: Sridharan S N Date: Fri, 23 Jun 2023 10:27:57 +0530 Subject: [PATCH 0082/3445] mtd: spinand: toshiba: add support for T{C,H}58NYG{0,2}S3HBAI4 and TH58NYG3S0HBAI6 Add support for: TC58NYG0S3HBAI4 - 1Gb SLC NAND flash TH58NYG2S3HBAI4 - 4Gb SLC NAND flash TH58NYG3S0HBAI6 - 8Gb SLC NAND flash All of these has 8b/512b on-die ECC capability Signed-off-by: Sridharan S N Signed-off-by: Md Sadre Alam Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230623045757.30055-4-quic_sridsn@quicinc.com --- drivers/mtd/nand/spi/toshiba.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c index 7380b1ebaccd5..cd027b41dd581 100644 --- a/drivers/mtd/nand/spi/toshiba.c +++ b/drivers/mtd/nand/spi/toshiba.c @@ -266,6 +266,39 @@ static const struct spinand_info toshiba_spinand_table[] = { SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, tx58cxgxsxraix_ecc_get_status)), + /* 1.8V 1Gb (1st generation) */ + SPINAND_INFO("TC58NYG0S3HBAI4", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA1), + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, + tx58cxgxsxraix_ecc_get_status)), + /* 1.8V 4Gb (1st generation) */ + SPINAND_INFO("TH58NYG2S3HBAI4", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xAC), + NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 2, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_x4_variants, + &update_cache_x4_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, + tx58cxgxsxraix_ecc_get_status)), + /* 1.8V 8Gb (1st generation) */ + SPINAND_INFO("TH58NYG3S0HBAI6", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA3), + NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_x4_variants, + &update_cache_x4_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, + tx58cxgxsxraix_ecc_get_status)), }; static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = { -- GitLab From ecdaf0ee79156ce0c103cc1a7e38634fa0de6a5a Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 30 Jun 2023 18:58:30 +0200 Subject: [PATCH 0083/3445] nand: oxnas_nand: remove obsolete raw nand driver Due to lack of maintenance and stall of development for a few years now, and since no new features will ever be added upstream, remove support for OX810 and OX820 nand. Acked-by: Linus Walleij Acked-by: Arnd Bergmann Acked-by: Daniel Golle Signed-off-by: Neil Armstrong Acked-by: Miquel Raynal Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230630-topic-oxnas-upstream-remove-v2-5-fb6ab3dea87c@linaro.org --- drivers/mtd/nand/raw/Kconfig | 7 - drivers/mtd/nand/raw/Makefile | 1 - drivers/mtd/nand/raw/oxnas_nand.c | 209 ------------------------------ 3 files changed, 217 deletions(-) delete mode 100644 drivers/mtd/nand/raw/oxnas_nand.c diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index b523354dfb00c..5b871e2f5c5e4 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -204,13 +204,6 @@ config MTD_NAND_BCM47XXNFLASH registered by bcma as platform devices. This enables driver for NAND flash memories. For now only BCM4706 is supported. -config MTD_NAND_OXNAS - tristate "Oxford Semiconductor NAND controller" - depends on ARCH_OXNAS || COMPILE_TEST - depends on HAS_IOMEM - help - This enables the NAND flash controller on Oxford Semiconductor SoCs. - config MTD_NAND_MPC5121_NFC tristate "MPC5121 NAND controller" depends on PPC_MPC512x diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index d93e861d8ba7a..25120a4afadac 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -26,7 +26,6 @@ obj-$(CONFIG_MTD_NAND_MARVELL) += marvell_nand.o obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o -obj-$(CONFIG_MTD_NAND_OXNAS) += oxnas_nand.o obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o diff --git a/drivers/mtd/nand/raw/oxnas_nand.c b/drivers/mtd/nand/raw/oxnas_nand.c deleted file mode 100644 index e3c9807df1cd8..0000000000000 --- a/drivers/mtd/nand/raw/oxnas_nand.c +++ /dev/null @@ -1,209 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Oxford Semiconductor OXNAS NAND driver - - * Copyright (C) 2016 Neil Armstrong - * Heavily based on plat_nand.c : - * Author: Vitaly Wool - * Copyright (C) 2013 Ma Haijun - * Copyright (C) 2012 John Crispin - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Nand commands */ -#define OXNAS_NAND_CMD_ALE BIT(18) -#define OXNAS_NAND_CMD_CLE BIT(19) - -#define OXNAS_NAND_MAX_CHIPS 1 - -struct oxnas_nand_ctrl { - struct nand_controller base; - void __iomem *io_base; - struct clk *clk; - struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS]; - unsigned int nchips; -}; - -static uint8_t oxnas_nand_read_byte(struct nand_chip *chip) -{ - struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip); - - return readb(oxnas->io_base); -} - -static void oxnas_nand_read_buf(struct nand_chip *chip, u8 *buf, int len) -{ - struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip); - - ioread8_rep(oxnas->io_base, buf, len); -} - -static void oxnas_nand_write_buf(struct nand_chip *chip, const u8 *buf, - int len) -{ - struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip); - - iowrite8_rep(oxnas->io_base, buf, len); -} - -/* Single CS command control */ -static void oxnas_nand_cmd_ctrl(struct nand_chip *chip, int cmd, - unsigned int ctrl) -{ - struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip); - - if (ctrl & NAND_CLE) - writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_CLE); - else if (ctrl & NAND_ALE) - writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_ALE); -} - -/* - * Probe for the NAND device. - */ -static int oxnas_nand_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct device_node *nand_np; - struct oxnas_nand_ctrl *oxnas; - struct nand_chip *chip; - struct mtd_info *mtd; - int count = 0; - int err = 0; - int i; - - /* Allocate memory for the device structure (and zero it) */ - oxnas = devm_kzalloc(&pdev->dev, sizeof(*oxnas), - GFP_KERNEL); - if (!oxnas) - return -ENOMEM; - - nand_controller_init(&oxnas->base); - - oxnas->io_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(oxnas->io_base)) - return PTR_ERR(oxnas->io_base); - - oxnas->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(oxnas->clk)) - oxnas->clk = NULL; - - /* Only a single chip node is supported */ - count = of_get_child_count(np); - if (count > 1) - return -EINVAL; - - err = clk_prepare_enable(oxnas->clk); - if (err) - return err; - - device_reset_optional(&pdev->dev); - - for_each_child_of_node(np, nand_np) { - chip = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip), - GFP_KERNEL); - if (!chip) { - err = -ENOMEM; - goto err_release_child; - } - - chip->controller = &oxnas->base; - - nand_set_flash_node(chip, nand_np); - nand_set_controller_data(chip, oxnas); - - mtd = nand_to_mtd(chip); - mtd->dev.parent = &pdev->dev; - mtd->priv = chip; - - chip->legacy.cmd_ctrl = oxnas_nand_cmd_ctrl; - chip->legacy.read_buf = oxnas_nand_read_buf; - chip->legacy.read_byte = oxnas_nand_read_byte; - chip->legacy.write_buf = oxnas_nand_write_buf; - chip->legacy.chip_delay = 30; - - /* Scan to find existence of the device */ - err = nand_scan(chip, 1); - if (err) - goto err_release_child; - - err = mtd_device_register(mtd, NULL, 0); - if (err) - goto err_cleanup_nand; - - oxnas->chips[oxnas->nchips++] = chip; - } - - /* Exit if no chips found */ - if (!oxnas->nchips) { - err = -ENODEV; - goto err_clk_unprepare; - } - - platform_set_drvdata(pdev, oxnas); - - return 0; - -err_cleanup_nand: - nand_cleanup(chip); -err_release_child: - of_node_put(nand_np); - - for (i = 0; i < oxnas->nchips; i++) { - chip = oxnas->chips[i]; - WARN_ON(mtd_device_unregister(nand_to_mtd(chip))); - nand_cleanup(chip); - } - -err_clk_unprepare: - clk_disable_unprepare(oxnas->clk); - return err; -} - -static void oxnas_nand_remove(struct platform_device *pdev) -{ - struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev); - struct nand_chip *chip; - int i; - - for (i = 0; i < oxnas->nchips; i++) { - chip = oxnas->chips[i]; - WARN_ON(mtd_device_unregister(nand_to_mtd(chip))); - nand_cleanup(chip); - } - - clk_disable_unprepare(oxnas->clk); -} - -static const struct of_device_id oxnas_nand_match[] = { - { .compatible = "oxsemi,ox820-nand" }, - {}, -}; -MODULE_DEVICE_TABLE(of, oxnas_nand_match); - -static struct platform_driver oxnas_nand_driver = { - .probe = oxnas_nand_probe, - .remove_new = oxnas_nand_remove, - .driver = { - .name = "oxnas_nand", - .of_match_table = oxnas_nand_match, - }, -}; - -module_platform_driver(oxnas_nand_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Neil Armstrong "); -MODULE_DESCRIPTION("Oxnas NAND driver"); -MODULE_ALIAS("platform:oxnas_nand"); -- GitLab From b7c9b576b5f61fe4b8705bf419a1fb09541e4be8 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 30 Jun 2023 18:58:31 +0200 Subject: [PATCH 0084/3445] dt-bindings: mtd: oxnas-nand: remove obsolete bindings Due to lack of maintenance and stall of development for a few years now, and since no new features will ever be added upstream, remove the for OX810 and OX820 nand bindings. Acked-by: Krzysztof Kozlowski Acked-by: Linus Walleij Acked-by: Arnd Bergmann Acked-by: Daniel Golle Signed-off-by: Neil Armstrong Acked-by: Miquel Raynal Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230630-topic-oxnas-upstream-remove-v2-6-fb6ab3dea87c@linaro.org --- .../devicetree/bindings/mtd/oxnas-nand.txt | 41 ------------------- 1 file changed, 41 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt deleted file mode 100644 index 2ba07fc8b79c9..0000000000000 --- a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt +++ /dev/null @@ -1,41 +0,0 @@ -* Oxford Semiconductor OXNAS NAND Controller - -Please refer to nand-controller.yaml for generic information regarding MTD NAND bindings. - -Required properties: - - compatible: "oxsemi,ox820-nand" - - reg: Base address and length for NAND mapped memory. - -Optional Properties: - - clocks: phandle to the NAND gate clock if needed. - - resets: phandle to the NAND reset control if needed. - -Example: - -nandc: nand-controller@41000000 { - compatible = "oxsemi,ox820-nand"; - reg = <0x41000000 0x100000>; - clocks = <&stdclk CLK_820_NAND>; - resets = <&reset RESET_NAND>; - #address-cells = <1>; - #size-cells = <0>; - - nand@0 { - reg = <0>; - #address-cells = <1>; - #size-cells = <1>; - nand-ecc-mode = "soft"; - nand-ecc-algo = "hamming"; - - partition@0 { - label = "boot"; - reg = <0x00000000 0x00e00000>; - read-only; - }; - - partition@e00000 { - label = "ubi"; - reg = <0x00e00000 0x07200000>; - }; - }; -}; -- GitLab From 079c8d9da26ed041a54706de68b754337e6df17e Mon Sep 17 00:00:00 2001 From: Arseniy Krasnov Date: Wed, 5 Jul 2023 13:43:57 +0300 Subject: [PATCH 0085/3445] mtd: rawnand: export 'nand_exit_status_op()' Export this function to work in pair with 'nand_status_op()' which is already exported. Signed-off-by: Arseniy Krasnov Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230705104403.696680-2-AVKrasnov@sberdevices.ru --- drivers/mtd/nand/raw/nand_base.c | 1 + include/linux/mtd/rawnand.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index a6af521832aa4..d4b55155aeae9 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -1885,6 +1885,7 @@ int nand_exit_status_op(struct nand_chip *chip) return 0; } +EXPORT_SYMBOL_GPL(nand_exit_status_op); /** * nand_erase_op - Do an erase operation diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 5159d692f9ce5..90a141ba2a5ac 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1540,6 +1540,7 @@ int nand_reset_op(struct nand_chip *chip); int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf, unsigned int len); int nand_status_op(struct nand_chip *chip, u8 *status); +int nand_exit_status_op(struct nand_chip *chip); int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock); int nand_read_page_op(struct nand_chip *chip, unsigned int page, unsigned int offset_in_page, void *buf, unsigned int len); -- GitLab From cda24ab77374ea823af413249eb19ff5f49bf9ad Mon Sep 17 00:00:00 2001 From: Arseniy Krasnov Date: Wed, 5 Jul 2023 13:43:58 +0300 Subject: [PATCH 0086/3445] mtd: rawnand: meson: use NAND core API to check status NAND core API already has functions to send NAND_CMD_STATUS and leave status checking mode by sending NAND_CMD_READ0, so use both of them instead of direct access to the controller registers. Signed-off-by: Arseniy Krasnov Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230705104403.696680-3-AVKrasnov@sberdevices.ru --- drivers/mtd/nand/raw/meson_nand.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c index d3faf80866314..91eeac49d18fe 100644 --- a/drivers/mtd/nand/raw/meson_nand.c +++ b/drivers/mtd/nand/raw/meson_nand.c @@ -400,9 +400,10 @@ static void meson_nfc_set_data_oob(struct nand_chip *nand, } } -static int meson_nfc_wait_no_rb_pin(struct meson_nfc *nfc, int timeout_ms, +static int meson_nfc_wait_no_rb_pin(struct nand_chip *nand, int timeout_ms, bool need_cmd_read0) { + struct meson_nfc *nfc = nand_get_controller_data(nand); u32 cmd, cfg; meson_nfc_cmd_idle(nfc, nfc->timing.twb); @@ -414,8 +415,7 @@ static int meson_nfc_wait_no_rb_pin(struct meson_nfc *nfc, int timeout_ms, writel(cfg, nfc->reg_base + NFC_REG_CFG); reinit_completion(&nfc->completion); - cmd = nfc->param.chip_select | NFC_CMD_CLE | NAND_CMD_STATUS; - writel(cmd, nfc->reg_base + NFC_REG_CMD); + nand_status_op(nand, NULL); /* use the max erase time as the maximum clock for waiting R/B */ cmd = NFC_CMD_RB | NFC_CMD_RB_INT_NO_PIN | nfc->timing.tbers_max; @@ -425,12 +425,8 @@ static int meson_nfc_wait_no_rb_pin(struct meson_nfc *nfc, int timeout_ms, msecs_to_jiffies(timeout_ms))) return -ETIMEDOUT; - if (need_cmd_read0) { - cmd = nfc->param.chip_select | NFC_CMD_CLE | NAND_CMD_READ0; - writel(cmd, nfc->reg_base + NFC_REG_CMD); - meson_nfc_drain_cmd(nfc); - meson_nfc_wait_cmd_finish(nfc, CMD_FIFO_EMPTY_TIMEOUT); - } + if (need_cmd_read0) + nand_exit_status_op(nand); return 0; } @@ -463,9 +459,11 @@ static int meson_nfc_wait_rb_pin(struct meson_nfc *nfc, int timeout_ms) return ret; } -static int meson_nfc_queue_rb(struct meson_nfc *nfc, int timeout_ms, +static int meson_nfc_queue_rb(struct nand_chip *nand, int timeout_ms, bool need_cmd_read0) { + struct meson_nfc *nfc = nand_get_controller_data(nand); + if (nfc->no_rb_pin) { /* This mode is used when there is no wired R/B pin. * It works like 'nand_soft_waitrdy()', but instead of @@ -477,7 +475,7 @@ static int meson_nfc_queue_rb(struct meson_nfc *nfc, int timeout_ms, * needed (for all cases except page programming - this * is reason of 'need_cmd_read0' flag). */ - return meson_nfc_wait_no_rb_pin(nfc, timeout_ms, + return meson_nfc_wait_no_rb_pin(nand, timeout_ms, need_cmd_read0); } else { return meson_nfc_wait_rb_pin(nfc, timeout_ms); @@ -687,7 +685,7 @@ static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand, if (in) { nfc->cmdfifo.rw.cmd1 = cs | NFC_CMD_CLE | NAND_CMD_READSTART; writel(nfc->cmdfifo.rw.cmd1, nfc->reg_base + NFC_REG_CMD); - meson_nfc_queue_rb(nfc, PSEC_TO_MSEC(sdr->tR_max), true); + meson_nfc_queue_rb(nand, PSEC_TO_MSEC(sdr->tR_max), true); } else { meson_nfc_cmd_idle(nfc, nfc->timing.tadl); } @@ -733,7 +731,7 @@ static int meson_nfc_write_page_sub(struct nand_chip *nand, cmd = nfc->param.chip_select | NFC_CMD_CLE | NAND_CMD_PAGEPROG; writel(cmd, nfc->reg_base + NFC_REG_CMD); - meson_nfc_queue_rb(nfc, PSEC_TO_MSEC(sdr->tPROG_max), false); + meson_nfc_queue_rb(nand, PSEC_TO_MSEC(sdr->tPROG_max), false); meson_nfc_dma_buffer_release(nand, data_len, info_len, DMA_TO_DEVICE); @@ -1049,7 +1047,7 @@ static int meson_nfc_exec_op(struct nand_chip *nand, break; case NAND_OP_WAITRDY_INSTR: - meson_nfc_queue_rb(nfc, instr->ctx.waitrdy.timeout_ms, + meson_nfc_queue_rb(nand, instr->ctx.waitrdy.timeout_ms, true); if (instr->delay_ns) meson_nfc_cmd_idle(nfc, delay_idle); -- GitLab From 2ec2839a9062db8a592525a3fdabd42dcd9a3a9b Mon Sep 17 00:00:00 2001 From: William Zhang Date: Thu, 6 Jul 2023 11:29:05 -0700 Subject: [PATCH 0087/3445] mtd: rawnand: brcmnand: Fix ECC level field setting for v7.2 controller v7.2 controller has different ECC level field size and shift in the acc control register than its predecessor and successor controller. It needs to be set specifically. Fixes: decba6d47869 ("mtd: brcmnand: Add v7.2 controller support") Signed-off-by: William Zhang Reviewed-by: Florian Fainelli Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230706182909.79151-2-william.zhang@broadcom.com --- drivers/mtd/nand/raw/brcmnand/brcmnand.c | 74 +++++++++++++----------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 2e9c2e2d9c9f7..9ea96911d16b9 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -272,6 +272,7 @@ struct brcmnand_controller { const unsigned int *page_sizes; unsigned int page_size_shift; unsigned int max_oob; + u32 ecc_level_shift; u32 features; /* for low-power standby/resume only */ @@ -596,6 +597,34 @@ enum { INTFC_CTLR_READY = BIT(31), }; +/*********************************************************************** + * NAND ACC CONTROL bitfield + * + * Some bits have remained constant throughout hardware revision, while + * others have shifted around. + ***********************************************************************/ + +/* Constant for all versions (where supported) */ +enum { + /* See BRCMNAND_HAS_CACHE_MODE */ + ACC_CONTROL_CACHE_MODE = BIT(22), + + /* See BRCMNAND_HAS_PREFETCH */ + ACC_CONTROL_PREFETCH = BIT(23), + + ACC_CONTROL_PAGE_HIT = BIT(24), + ACC_CONTROL_WR_PREEMPT = BIT(25), + ACC_CONTROL_PARTIAL_PAGE = BIT(26), + ACC_CONTROL_RD_ERASED = BIT(27), + ACC_CONTROL_FAST_PGM_RDIN = BIT(28), + ACC_CONTROL_WR_ECC = BIT(30), + ACC_CONTROL_RD_ECC = BIT(31), +}; + +#define ACC_CONTROL_ECC_SHIFT 16 +/* Only for v7.2 */ +#define ACC_CONTROL_ECC_EXT_SHIFT 13 + static inline bool brcmnand_non_mmio_ops(struct brcmnand_controller *ctrl) { #if IS_ENABLED(CONFIG_MTD_NAND_BRCMNAND_BCMA) @@ -737,6 +766,12 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl) else if (of_property_read_bool(ctrl->dev->of_node, "brcm,nand-has-wp")) ctrl->features |= BRCMNAND_HAS_WP; + /* v7.2 has different ecc level shift in the acc register */ + if (ctrl->nand_version == 0x0702) + ctrl->ecc_level_shift = ACC_CONTROL_ECC_EXT_SHIFT; + else + ctrl->ecc_level_shift = ACC_CONTROL_ECC_SHIFT; + return 0; } @@ -931,30 +966,6 @@ static inline int brcmnand_cmd_shift(struct brcmnand_controller *ctrl) return 0; } -/*********************************************************************** - * NAND ACC CONTROL bitfield - * - * Some bits have remained constant throughout hardware revision, while - * others have shifted around. - ***********************************************************************/ - -/* Constant for all versions (where supported) */ -enum { - /* See BRCMNAND_HAS_CACHE_MODE */ - ACC_CONTROL_CACHE_MODE = BIT(22), - - /* See BRCMNAND_HAS_PREFETCH */ - ACC_CONTROL_PREFETCH = BIT(23), - - ACC_CONTROL_PAGE_HIT = BIT(24), - ACC_CONTROL_WR_PREEMPT = BIT(25), - ACC_CONTROL_PARTIAL_PAGE = BIT(26), - ACC_CONTROL_RD_ERASED = BIT(27), - ACC_CONTROL_FAST_PGM_RDIN = BIT(28), - ACC_CONTROL_WR_ECC = BIT(30), - ACC_CONTROL_RD_ECC = BIT(31), -}; - static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl) { if (ctrl->nand_version == 0x0702) @@ -967,18 +978,15 @@ static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl) return GENMASK(4, 0); } -#define NAND_ACC_CONTROL_ECC_SHIFT 16 -#define NAND_ACC_CONTROL_ECC_EXT_SHIFT 13 - static inline u32 brcmnand_ecc_level_mask(struct brcmnand_controller *ctrl) { u32 mask = (ctrl->nand_version >= 0x0600) ? 0x1f : 0x0f; - mask <<= NAND_ACC_CONTROL_ECC_SHIFT; + mask <<= ACC_CONTROL_ECC_SHIFT; /* v7.2 includes additional ECC levels */ - if (ctrl->nand_version >= 0x0702) - mask |= 0x7 << NAND_ACC_CONTROL_ECC_EXT_SHIFT; + if (ctrl->nand_version == 0x0702) + mask |= 0x7 << ACC_CONTROL_ECC_EXT_SHIFT; return mask; } @@ -992,8 +1000,8 @@ static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en) if (en) { acc_control |= ecc_flags; /* enable RD/WR ECC */ - acc_control |= host->hwcfg.ecc_level - << NAND_ACC_CONTROL_ECC_SHIFT; + acc_control &= ~brcmnand_ecc_level_mask(ctrl); + acc_control |= host->hwcfg.ecc_level << ctrl->ecc_level_shift; } else { acc_control &= ~ecc_flags; /* disable RD/WR ECC */ acc_control &= ~brcmnand_ecc_level_mask(ctrl); @@ -2561,7 +2569,7 @@ static int brcmnand_set_cfg(struct brcmnand_host *host, tmp &= ~brcmnand_ecc_level_mask(ctrl); tmp &= ~brcmnand_spare_area_mask(ctrl); if (ctrl->nand_version >= 0x0302) { - tmp |= cfg->ecc_level << NAND_ACC_CONTROL_ECC_SHIFT; + tmp |= cfg->ecc_level << ctrl->ecc_level_shift; tmp |= cfg->spare_area_size; } nand_writereg(ctrl, acc_control_offs, tmp); -- GitLab From 9cc0a598b944816f2968baf2631757f22721b996 Mon Sep 17 00:00:00 2001 From: William Zhang Date: Thu, 6 Jul 2023 11:29:06 -0700 Subject: [PATCH 0088/3445] mtd: rawnand: brcmnand: Fix potential false time out warning If system is busy during the command status polling function, the driver may not get the chance to poll the status register till the end of time out and return the premature status. Do a final check after time out happens to ensure reading the correct status. Fixes: 9d2ee0a60b8b ("mtd: nand: brcmnand: Check flash #WP pin status before nand erase/program") Signed-off-by: William Zhang Reviewed-by: Florian Fainelli Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230706182909.79151-3-william.zhang@broadcom.com --- drivers/mtd/nand/raw/brcmnand/brcmnand.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 9ea96911d16b9..9a373a10304d8 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -1080,6 +1080,14 @@ static int bcmnand_ctrl_poll_status(struct brcmnand_controller *ctrl, cpu_relax(); } while (time_after(limit, jiffies)); + /* + * do a final check after time out in case the CPU was busy and the driver + * did not get enough time to perform the polling to avoid false alarms + */ + val = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS); + if ((val & mask) == expected_val) + return 0; + dev_warn(ctrl->dev, "timeout on status poll (expected %x got %x)\n", expected_val, val & mask); -- GitLab From e66dd317194daae0475fe9e5577c80aa97f16cb9 Mon Sep 17 00:00:00 2001 From: William Zhang Date: Thu, 6 Jul 2023 11:29:07 -0700 Subject: [PATCH 0089/3445] mtd: rawnand: brcmnand: Fix crash during the panic_write When executing a NAND command within the panic write path, wait for any pending command instead of calling BUG_ON to avoid crashing while already crashing. Fixes: 27c5b17cd1b1 ("mtd: nand: add NAND driver "library" for Broadcom STB NAND controller") Signed-off-by: William Zhang Reviewed-by: Florian Fainelli Reviewed-by: Kursad Oney Reviewed-by: Kamal Dasu Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230706182909.79151-4-william.zhang@broadcom.com --- drivers/mtd/nand/raw/brcmnand/brcmnand.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 9a373a10304d8..b2c6396060db7 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -1608,7 +1608,17 @@ static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd) dev_dbg(ctrl->dev, "send native cmd %d addr 0x%llx\n", cmd, cmd_addr); - BUG_ON(ctrl->cmd_pending != 0); + /* + * If we came here through _panic_write and there is a pending + * command, try to wait for it. If it times out, rather than + * hitting BUG_ON, just return so we don't crash while crashing. + */ + if (oops_in_progress) { + if (ctrl->cmd_pending && + bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY, NAND_CTRL_RDY, 0)) + return; + } else + BUG_ON(ctrl->cmd_pending != 0); ctrl->cmd_pending = cmd; ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY, NAND_CTRL_RDY, 0); -- GitLab From 5d53244186c9ac58cb88d76a0958ca55b83a15cd Mon Sep 17 00:00:00 2001 From: William Zhang Date: Thu, 6 Jul 2023 11:29:08 -0700 Subject: [PATCH 0090/3445] mtd: rawnand: brcmnand: Fix potential out-of-bounds access in oob write When the oob buffer length is not in multiple of words, the oob write function does out-of-bounds read on the oob source buffer at the last iteration. Fix that by always checking length limit on the oob buffer read and fill with 0xff when reaching the end of the buffer to the oob registers. Fixes: 27c5b17cd1b1 ("mtd: nand: add NAND driver "library" for Broadcom STB NAND controller") Signed-off-by: William Zhang Reviewed-by: Florian Fainelli Cc: stable@vger.kernel.org Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230706182909.79151-5-william.zhang@broadcom.com --- drivers/mtd/nand/raw/brcmnand/brcmnand.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index b2c6396060db7..71d0ba652bee5 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -1477,19 +1477,33 @@ static int write_oob_to_regs(struct brcmnand_controller *ctrl, int i, const u8 *oob, int sas, int sector_1k) { int tbytes = sas << sector_1k; - int j; + int j, k = 0; + u32 last = 0xffffffff; + u8 *plast = (u8 *)&last; /* Adjust OOB values for 1K sector size */ if (sector_1k && (i & 0x01)) tbytes = max(0, tbytes - (int)ctrl->max_oob); tbytes = min_t(int, tbytes, ctrl->max_oob); - for (j = 0; j < tbytes; j += 4) + /* + * tbytes may not be multiple of words. Make sure we don't read out of + * the boundary and stop at last word. + */ + for (j = 0; (j + 3) < tbytes; j += 4) oob_reg_write(ctrl, j, (oob[j + 0] << 24) | (oob[j + 1] << 16) | (oob[j + 2] << 8) | (oob[j + 3] << 0)); + + /* handle the remaing bytes */ + while (j < tbytes) + plast[k++] = oob[j++]; + + if (tbytes & 0x3) + oob_reg_write(ctrl, (tbytes & ~0x3), (__force u32)cpu_to_be32(last)); + return tbytes; } -- GitLab From 60177390fa061c62d156f4a546e3efd90df3c183 Mon Sep 17 00:00:00 2001 From: William Zhang Date: Thu, 6 Jul 2023 11:29:09 -0700 Subject: [PATCH 0091/3445] mtd: rawnand: brcmnand: Fix mtd oobsize brcmnand controller can only access the flash spare area up to certain bytes based on the ECC level. It can be less than the actual flash spare area size. For example, for many NAND chip supporting ECC BCH-8, it has 226 bytes spare area. But controller can only uses 218 bytes. So brcmand driver overrides the mtd oobsize with the controller's accessible spare area size. When the nand base driver utilizes the nand_device object, it resets the oobsize back to the actual flash spare aprea size from nand_memory_organization structure and controller may not able to access all the oob area as mtd advises. This change fixes the issue by overriding the oobsize in the nand_memory_organization structure to the controller's accessible spare area size. Fixes: a7ab085d7c16 ("mtd: rawnand: Initialize the nand_device object") Signed-off-by: William Zhang Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230706182909.79151-6-william.zhang@broadcom.com --- drivers/mtd/nand/raw/brcmnand/brcmnand.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 71d0ba652bee5..39661e23d7d4f 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -2652,6 +2652,8 @@ static int brcmnand_setup_dev(struct brcmnand_host *host) struct nand_chip *chip = &host->chip; const struct nand_ecc_props *requirements = nanddev_get_ecc_requirements(&chip->base); + struct nand_memory_organization *memorg = + nanddev_get_memorg(&chip->base); struct brcmnand_controller *ctrl = host->ctrl; struct brcmnand_cfg *cfg = &host->hwcfg; char msg[128]; @@ -2673,10 +2675,11 @@ static int brcmnand_setup_dev(struct brcmnand_host *host) if (cfg->spare_area_size > ctrl->max_oob) cfg->spare_area_size = ctrl->max_oob; /* - * Set oobsize to be consistent with controller's spare_area_size, as - * the rest is inaccessible. + * Set mtd and memorg oobsize to be consistent with controller's + * spare_area_size, as the rest is inaccessible. */ mtd->oobsize = cfg->spare_area_size * (mtd->writesize >> FC_SHIFT); + memorg->oobsize = mtd->oobsize; cfg->device_size = mtd->size; cfg->block_size = mtd->erasesize; -- GitLab From 52b4bdd28c861e7331543f4b5a0853b80c9fd3fa Mon Sep 17 00:00:00 2001 From: Yuanyuan Zhong Date: Thu, 29 Jun 2023 15:32:48 -0600 Subject: [PATCH 0092/3445] RDMA/mlx5: align MR mem allocation size to power-of-two The MR memory allocation requests extra bytes to guarantee that there is enough space to find the memory aligned to MLX5_UMR_ALIGN. For power-of-two sizes, the alignment can be guaranteed by kmalloc() according to commit 59bb47985c1d ("mm, sl[aou]b: guarantee natural alignment for kmalloc(power-of-two)"). So if target alignment is power-of-two and adding the extra bytes crosses a power-of-two boundary, use the next power-of-two as the allocation size. Signed-off-by: Yuanyuan Zhong Link: https://lore.kernel.org/r/20230629213248.3184245-2-yzhong@purestorage.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/mlx5/mr.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 2017ede100a62..92f35fafb2c0c 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -1766,6 +1766,11 @@ mlx5_alloc_priv_descs(struct ib_device *device, int ret; add_size = max_t(int, MLX5_UMR_ALIGN - ARCH_KMALLOC_MINALIGN, 0); + if (is_power_of_2(MLX5_UMR_ALIGN) && add_size) { + int end = max_t(int, MLX5_UMR_ALIGN, roundup_pow_of_two(size)); + + add_size = min_t(int, end - size, add_size); + } mr->descs_alloc = kzalloc(size + add_size, GFP_KERNEL); if (!mr->descs_alloc) -- GitLab From 113383eff3ff6f6ea6fcddeb469d10d21c8e3d35 Mon Sep 17 00:00:00 2001 From: Michael Margolin Date: Mon, 3 Jul 2023 15:34:04 +0000 Subject: [PATCH 0093/3445] RDMA/efa: Add RDMA write HW statistics counters Update device API and request RDMA write counters if RDMA write is supported by device. Expose newly added counters through ib core counters mechanism. Reviewed-by: Daniel Kranzdorf Reviewed-by: Yonatan Nachum Signed-off-by: Michael Margolin Link: https://lore.kernel.org/r/20230703153404.30877-1-mrgolin@amazon.com Reviewed-by: Gal Pressman Signed-off-by: Leon Romanovsky --- .../infiniband/hw/efa/efa_admin_cmds_defs.h | 13 +++++++++++++ drivers/infiniband/hw/efa/efa_com_cmd.c | 8 +++++++- drivers/infiniband/hw/efa/efa_com_cmd.h | 10 +++++++++- drivers/infiniband/hw/efa/efa_verbs.c | 18 ++++++++++++++++++ 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h b/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h index 4e93ef7f84ee8..9c65bd27bae09 100644 --- a/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h +++ b/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h @@ -66,6 +66,7 @@ enum efa_admin_get_stats_type { EFA_ADMIN_GET_STATS_TYPE_BASIC = 0, EFA_ADMIN_GET_STATS_TYPE_MESSAGES = 1, EFA_ADMIN_GET_STATS_TYPE_RDMA_READ = 2, + EFA_ADMIN_GET_STATS_TYPE_RDMA_WRITE = 3, }; enum efa_admin_get_stats_scope { @@ -570,6 +571,16 @@ struct efa_admin_rdma_read_stats { u64 read_resp_bytes; }; +struct efa_admin_rdma_write_stats { + u64 write_wrs; + + u64 write_bytes; + + u64 write_wr_err; + + u64 write_recv_bytes; +}; + struct efa_admin_acq_get_stats_resp { struct efa_admin_acq_common_desc acq_common_desc; @@ -579,6 +590,8 @@ struct efa_admin_acq_get_stats_resp { struct efa_admin_messages_stats messages_stats; struct efa_admin_rdma_read_stats rdma_read_stats; + + struct efa_admin_rdma_write_stats rdma_write_stats; } u; }; diff --git a/drivers/infiniband/hw/efa/efa_com_cmd.c b/drivers/infiniband/hw/efa/efa_com_cmd.c index 8f8885e002ba4..576811885d59e 100644 --- a/drivers/infiniband/hw/efa/efa_com_cmd.c +++ b/drivers/infiniband/hw/efa/efa_com_cmd.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause /* - * Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All rights reserved. + * Copyright 2018-2023 Amazon.com, Inc. or its affiliates. All rights reserved. */ #include "efa_com.h" @@ -794,6 +794,12 @@ int efa_com_get_stats(struct efa_com_dev *edev, result->rdma_read_stats.read_wr_err = resp.u.rdma_read_stats.read_wr_err; result->rdma_read_stats.read_resp_bytes = resp.u.rdma_read_stats.read_resp_bytes; break; + case EFA_ADMIN_GET_STATS_TYPE_RDMA_WRITE: + result->rdma_write_stats.write_wrs = resp.u.rdma_write_stats.write_wrs; + result->rdma_write_stats.write_bytes = resp.u.rdma_write_stats.write_bytes; + result->rdma_write_stats.write_wr_err = resp.u.rdma_write_stats.write_wr_err; + result->rdma_write_stats.write_recv_bytes = resp.u.rdma_write_stats.write_recv_bytes; + break; } return 0; diff --git a/drivers/infiniband/hw/efa/efa_com_cmd.h b/drivers/infiniband/hw/efa/efa_com_cmd.h index 0898ad5bc3405..fc97f37bb39bb 100644 --- a/drivers/infiniband/hw/efa/efa_com_cmd.h +++ b/drivers/infiniband/hw/efa/efa_com_cmd.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ /* - * Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All rights reserved. + * Copyright 2018-2023 Amazon.com, Inc. or its affiliates. All rights reserved. */ #ifndef _EFA_COM_CMD_H_ @@ -262,10 +262,18 @@ struct efa_com_rdma_read_stats { u64 read_resp_bytes; }; +struct efa_com_rdma_write_stats { + u64 write_wrs; + u64 write_bytes; + u64 write_wr_err; + u64 write_recv_bytes; +}; + union efa_com_get_stats_result { struct efa_com_basic_stats basic_stats; struct efa_com_messages_stats messages_stats; struct efa_com_rdma_read_stats rdma_read_stats; + struct efa_com_rdma_write_stats rdma_write_stats; }; int efa_com_create_qp(struct efa_com_dev *edev, diff --git a/drivers/infiniband/hw/efa/efa_verbs.c b/drivers/infiniband/hw/efa/efa_verbs.c index 2a195c4b0f17d..7a27d79c0541f 100644 --- a/drivers/infiniband/hw/efa/efa_verbs.c +++ b/drivers/infiniband/hw/efa/efa_verbs.c @@ -61,6 +61,10 @@ struct efa_user_mmap_entry { op(EFA_RDMA_READ_BYTES, "rdma_read_bytes") \ op(EFA_RDMA_READ_WR_ERR, "rdma_read_wr_err") \ op(EFA_RDMA_READ_RESP_BYTES, "rdma_read_resp_bytes") \ + op(EFA_RDMA_WRITE_WRS, "rdma_write_wrs") \ + op(EFA_RDMA_WRITE_BYTES, "rdma_write_bytes") \ + op(EFA_RDMA_WRITE_WR_ERR, "rdma_write_wr_err") \ + op(EFA_RDMA_WRITE_RECV_BYTES, "rdma_write_recv_bytes") \ #define EFA_STATS_ENUM(ename, name) ename, #define EFA_STATS_STR(ename, nam) \ @@ -2080,6 +2084,7 @@ static int efa_fill_port_stats(struct efa_dev *dev, struct rdma_hw_stats *stats, { struct efa_com_get_stats_params params = {}; union efa_com_get_stats_result result; + struct efa_com_rdma_write_stats *rws; struct efa_com_rdma_read_stats *rrs; struct efa_com_messages_stats *ms; struct efa_com_basic_stats *bs; @@ -2121,6 +2126,19 @@ static int efa_fill_port_stats(struct efa_dev *dev, struct rdma_hw_stats *stats, stats->value[EFA_RDMA_READ_WR_ERR] = rrs->read_wr_err; stats->value[EFA_RDMA_READ_RESP_BYTES] = rrs->read_resp_bytes; + if (EFA_DEV_CAP(dev, RDMA_WRITE)) { + params.type = EFA_ADMIN_GET_STATS_TYPE_RDMA_WRITE; + err = efa_com_get_stats(&dev->edev, ¶ms, &result); + if (err) + return err; + + rws = &result.rdma_write_stats; + stats->value[EFA_RDMA_WRITE_WRS] = rws->write_wrs; + stats->value[EFA_RDMA_WRITE_BYTES] = rws->write_bytes; + stats->value[EFA_RDMA_WRITE_WR_ERR] = rws->write_wr_err; + stats->value[EFA_RDMA_WRITE_RECV_BYTES] = rws->write_recv_bytes; + } + return ARRAY_SIZE(efa_port_stats_descs); } -- GitLab From 81a16e154cc03e3ec76537694ab4afb8df3965eb Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Fri, 7 Jul 2023 12:06:05 +0800 Subject: [PATCH 0094/3445] mtd: rawnand: sunxi: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Acked-by: Jernej Skrabec Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230707040622.78174-1-frank.li@vivo.com --- drivers/mtd/nand/raw/sunxi_nand.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index 9884304634f68..db36bd755b8d9 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -2087,8 +2087,7 @@ static int sunxi_nfc_probe(struct platform_device *pdev) nand_controller_init(&nfc->controller); INIT_LIST_HEAD(&nfc->chips); - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - nfc->regs = devm_ioremap_resource(dev, r); + nfc->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &r); if (IS_ERR(nfc->regs)) return PTR_ERR(nfc->regs); -- GitLab From 1c66c7523f2fd2d9c8f81a2b7116252c323847a0 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Fri, 7 Jul 2023 12:06:06 +0800 Subject: [PATCH 0095/3445] mtd: rawnand: lpc32xx_slc: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230707040622.78174-2-frank.li@vivo.com --- drivers/mtd/nand/raw/lpc32xx_slc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c index 3139b6107660c..2201264d3c37d 100644 --- a/drivers/mtd/nand/raw/lpc32xx_slc.c +++ b/drivers/mtd/nand/raw/lpc32xx_slc.c @@ -836,8 +836,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) if (!host) return -ENOMEM; - rc = platform_get_resource(pdev, IORESOURCE_MEM, 0); - host->io_base = devm_ioremap_resource(&pdev->dev, rc); + host->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, &rc); if (IS_ERR(host->io_base)) return PTR_ERR(host->io_base); -- GitLab From c96b3e0905b41cbf8e369faa1e4decded58860b5 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Fri, 7 Jul 2023 12:06:07 +0800 Subject: [PATCH 0096/3445] mtd: rawnand: mxc: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230707040622.78174-3-frank.li@vivo.com --- drivers/mtd/nand/raw/mxc_nand.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c index 3d4b2e8294ea6..2f8dcda0f4357 100644 --- a/drivers/mtd/nand/raw/mxc_nand.c +++ b/drivers/mtd/nand/raw/mxc_nand.c @@ -1696,7 +1696,6 @@ static int mxcnd_probe(struct platform_device *pdev) struct nand_chip *this; struct mtd_info *mtd; struct mxc_nand_host *host; - struct resource *res; int err = 0; /* Allocate memory for MTD device structure and private data */ @@ -1740,17 +1739,15 @@ static int mxcnd_probe(struct platform_device *pdev) this->options |= NAND_KEEP_TIMINGS; if (host->devtype_data->needs_ip) { - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - host->regs_ip = devm_ioremap_resource(&pdev->dev, res); + host->regs_ip = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(host->regs_ip)) return PTR_ERR(host->regs_ip); - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + host->base = devm_platform_ioremap_resource(pdev, 1); } else { - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + host->base = devm_platform_ioremap_resource(pdev, 0); } - host->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(host->base)) return PTR_ERR(host->base); -- GitLab From 4eef841d29fac5fc8500668d1498a1ab8f9a91ce Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Fri, 7 Jul 2023 12:06:08 +0800 Subject: [PATCH 0097/3445] mtd: rawnand: sh_flctl: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230707040622.78174-4-frank.li@vivo.com --- drivers/mtd/nand/raw/sh_flctl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c index 63bf20c417197..db243b54c953e 100644 --- a/drivers/mtd/nand/raw/sh_flctl.c +++ b/drivers/mtd/nand/raw/sh_flctl.c @@ -1124,8 +1124,7 @@ static int flctl_probe(struct platform_device *pdev) if (!flctl) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - flctl->reg = devm_ioremap_resource(&pdev->dev, res); + flctl->reg = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(flctl->reg)) return PTR_ERR(flctl->reg); flctl->fifo = res->start + 0x24; /* FLDTFIFO */ -- GitLab From 189175e0c3554434416e75d7687011ef6c185159 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Fri, 7 Jul 2023 12:06:09 +0800 Subject: [PATCH 0098/3445] mtd: rawnand: omap2: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230707040622.78174-5-frank.li@vivo.com --- drivers/mtd/nand/raw/omap2.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c index db22b3af16d8a..277d16f1e0bb2 100644 --- a/drivers/mtd/nand/raw/omap2.c +++ b/drivers/mtd/nand/raw/omap2.c @@ -2219,8 +2219,7 @@ static int omap_nand_probe(struct platform_device *pdev) } } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - vaddr = devm_ioremap_resource(&pdev->dev, res); + vaddr = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(vaddr)) return PTR_ERR(vaddr); -- GitLab From 68e10224a5ee9de5867152da8086acd543263c29 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Fri, 7 Jul 2023 12:06:10 +0800 Subject: [PATCH 0099/3445] mtd: rawnand: stm32_fmc2: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230707040622.78174-6-frank.li@vivo.com --- drivers/mtd/nand/raw/stm32_fmc2_nand.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index 10c11cecac080..2f9e43f64dd77 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -1922,8 +1922,8 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev) if (!(nfc->cs_assigned & BIT(chip_cs))) continue; - res = platform_get_resource(pdev, IORESOURCE_MEM, mem_region); - nfc->data_base[chip_cs] = devm_ioremap_resource(dev, res); + nfc->data_base[chip_cs] = devm_platform_get_and_ioremap_resource(pdev, + mem_region, &res); if (IS_ERR(nfc->data_base[chip_cs])) return PTR_ERR(nfc->data_base[chip_cs]); -- GitLab From 9cd9dda8f06c9100997e981f11e8ef9cec042a95 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Fri, 7 Jul 2023 12:06:11 +0800 Subject: [PATCH 0100/3445] mtd: rawnand: lpc32xx_mlc: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230707040622.78174-7-frank.li@vivo.com --- drivers/mtd/nand/raw/lpc32xx_mlc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c index b3136ae6f4e94..488fd452611a6 100644 --- a/drivers/mtd/nand/raw/lpc32xx_mlc.c +++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c @@ -695,8 +695,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) host->pdev = pdev; - rc = platform_get_resource(pdev, IORESOURCE_MEM, 0); - host->io_base = devm_ioremap_resource(&pdev->dev, rc); + host->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, &rc); if (IS_ERR(host->io_base)) return PTR_ERR(host->io_base); -- GitLab From 892ad2638a6ba33c0b5afb335501b9bb7e8a83b6 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Fri, 7 Jul 2023 12:06:12 +0800 Subject: [PATCH 0101/3445] mtd: rawnand: fsl_upm: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230707040622.78174-8-frank.li@vivo.com --- drivers/mtd/nand/raw/fsl_upm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c index 086426139173f..f1810e2f2c07d 100644 --- a/drivers/mtd/nand/raw/fsl_upm.c +++ b/drivers/mtd/nand/raw/fsl_upm.c @@ -172,8 +172,7 @@ static int fun_probe(struct platform_device *ofdev) if (!fun) return -ENOMEM; - io_res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); - fun->io_base = devm_ioremap_resource(&ofdev->dev, io_res); + fun->io_base = devm_platform_get_and_ioremap_resource(ofdev, 0, &io_res); if (IS_ERR(fun->io_base)) return PTR_ERR(fun->io_base); -- GitLab From 09ea085f6414e3c0d8ff034e941fe30216bd6f89 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Fri, 7 Jul 2023 12:06:14 +0800 Subject: [PATCH 0102/3445] mtd: rawnand: atmel: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230707040622.78174-10-frank.li@vivo.com --- drivers/mtd/nand/raw/atmel/nand-controller.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index 81e3d682a8cde..3f494f7c7ecbd 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -1791,8 +1791,7 @@ atmel_nand_controller_legacy_add_nands(struct atmel_nand_controller *nc) nand->numcs = 1; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - nand->cs[0].io.virt = devm_ioremap_resource(dev, res); + nand->cs[0].io.virt = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(nand->cs[0].io.virt)) return PTR_ERR(nand->cs[0].io.virt); -- GitLab From 717a53833d0b0d735df82f041d1d000afa768cf8 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Fri, 7 Jul 2023 12:06:15 +0800 Subject: [PATCH 0103/3445] mtd: nand: samsung: Convert to devm_platform_ioremap_resource() and devm_platform_get_and_ioremap_resource() Use devm_platform_ioremap_resource() and devm_platform_get_and_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230707040622.78174-11-frank.li@vivo.com --- drivers/mtd/nand/onenand/onenand_samsung.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/onenand/onenand_samsung.c b/drivers/mtd/nand/onenand/onenand_samsung.c index 92151aa529647..fd6890a03d557 100644 --- a/drivers/mtd/nand/onenand/onenand_samsung.c +++ b/drivers/mtd/nand/onenand/onenand_samsung.c @@ -860,8 +860,7 @@ static int s3c_onenand_probe(struct platform_device *pdev) s3c_onenand_setup(mtd); - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - onenand->base = devm_ioremap_resource(&pdev->dev, r); + onenand->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r); if (IS_ERR(onenand->base)) return PTR_ERR(onenand->base); @@ -874,8 +873,7 @@ static int s3c_onenand_probe(struct platform_device *pdev) this->options |= ONENAND_SKIP_UNLOCK_CHECK; if (onenand->type != TYPE_S5PC110) { - r = platform_get_resource(pdev, IORESOURCE_MEM, 1); - onenand->ahb_addr = devm_ioremap_resource(&pdev->dev, r); + onenand->ahb_addr = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(onenand->ahb_addr)) return PTR_ERR(onenand->ahb_addr); @@ -895,8 +893,7 @@ static int s3c_onenand_probe(struct platform_device *pdev) this->subpagesize = mtd->writesize; } else { /* S5PC110 */ - r = platform_get_resource(pdev, IORESOURCE_MEM, 1); - onenand->dma_addr = devm_ioremap_resource(&pdev->dev, r); + onenand->dma_addr = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(onenand->dma_addr)) return PTR_ERR(onenand->dma_addr); -- GitLab From 0e0d59f2f6ba8f26a16081fb76d301fc369cea36 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Fri, 7 Jul 2023 12:06:17 +0800 Subject: [PATCH 0104/3445] mtd: plat-ram: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230707040622.78174-13-frank.li@vivo.com --- drivers/mtd/maps/plat-ram.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index cedd8ef9a6bf5..4c921dce73966 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -123,8 +123,7 @@ static int platram_probe(struct platform_device *pdev) info->pdata = pdata; /* get the resource for the memory mapping */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - info->map.virt = devm_ioremap_resource(&pdev->dev, res); + info->map.virt = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(info->map.virt)) { err = PTR_ERR(info->map.virt); goto exit_free; -- GitLab From 6145e07e9c77a99cfe98f10b6544beef8026ce28 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Fri, 7 Jul 2023 12:06:18 +0800 Subject: [PATCH 0105/3445] mtd: lantiq-flash: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230707040622.78174-14-frank.li@vivo.com --- drivers/mtd/maps/lantiq-flash.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c index 67a1dbfdd72ce..a1da1c8973c02 100644 --- a/drivers/mtd/maps/lantiq-flash.c +++ b/drivers/mtd/maps/lantiq-flash.c @@ -118,11 +118,9 @@ ltq_mtd_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ltq_mtd); - ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!ltq_mtd->res) { - dev_err(&pdev->dev, "failed to get memory resource\n"); - return -ENOENT; - } + ltq_mtd->map->virt = devm_platform_get_and_ioremap_resource(pdev, 0, <q_mtd->res); + if (IS_ERR(ltq_mtd->map->virt)) + return PTR_ERR(ltq_mtd->map->virt); ltq_mtd->map = devm_kzalloc(&pdev->dev, sizeof(struct map_info), GFP_KERNEL); @@ -131,9 +129,6 @@ ltq_mtd_probe(struct platform_device *pdev) ltq_mtd->map->phys = ltq_mtd->res->start; ltq_mtd->map->size = resource_size(ltq_mtd->res); - ltq_mtd->map->virt = devm_ioremap_resource(&pdev->dev, ltq_mtd->res); - if (IS_ERR(ltq_mtd->map->virt)) - return PTR_ERR(ltq_mtd->map->virt); ltq_mtd->map->name = ltq_map_name; ltq_mtd->map->bankwidth = 2; -- GitLab From a29f696aa96f94ced1655b183c9694920d8bbfe2 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Fri, 7 Jul 2023 12:06:19 +0800 Subject: [PATCH 0106/3445] mtd: lpddr2_nvm: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230707040622.78174-15-frank.li@vivo.com --- drivers/mtd/lpddr/lpddr2_nvm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/lpddr/lpddr2_nvm.c b/drivers/mtd/lpddr/lpddr2_nvm.c index e71af4c490969..f4e5174b2449c 100644 --- a/drivers/mtd/lpddr/lpddr2_nvm.c +++ b/drivers/mtd/lpddr/lpddr2_nvm.c @@ -412,7 +412,6 @@ static int lpddr2_nvm_probe(struct platform_device *pdev) struct map_info *map; struct mtd_info *mtd; struct resource *add_range; - struct resource *control_regs; struct pcm_int_data *pcm_data; /* Allocate memory control_regs data structures */ @@ -452,8 +451,7 @@ static int lpddr2_nvm_probe(struct platform_device *pdev) simple_map_init(map); /* fill with default methods */ - control_regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); - pcm_data->ctl_regs = devm_ioremap_resource(&pdev->dev, control_regs); + pcm_data->ctl_regs = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(pcm_data->ctl_regs)) return PTR_ERR(pcm_data->ctl_regs); -- GitLab From 1726813c2efff24a78836dd6333cd213b28cd5fa Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Fri, 7 Jul 2023 12:06:20 +0800 Subject: [PATCH 0107/3445] mtd: st_spi_fsm: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230707040622.78174-16-frank.li@vivo.com --- drivers/mtd/devices/st_spi_fsm.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c index 3dbb1aa80bfa7..95530cbbb1e0d 100644 --- a/drivers/mtd/devices/st_spi_fsm.c +++ b/drivers/mtd/devices/st_spi_fsm.c @@ -2016,7 +2016,6 @@ static int stfsm_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct flash_info *info; - struct resource *res; struct stfsm *fsm; int ret; @@ -2033,18 +2032,9 @@ static int stfsm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, fsm); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Resource not found\n"); - return -ENODEV; - } - - fsm->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(fsm->base)) { - dev_err(&pdev->dev, - "Failed to reserve memory region %pR\n", res); + fsm->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(fsm->base)) return PTR_ERR(fsm->base); - } fsm->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(fsm->clk)) { -- GitLab From badd019b4a2a44815e976a0108dd8e52a1a24a83 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Fri, 7 Jul 2023 12:06:21 +0800 Subject: [PATCH 0108/3445] mtd: spear_smi: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230707040622.78174-17-frank.li@vivo.com --- drivers/mtd/devices/spear_smi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c index cc17133be2972..93bca52251167 100644 --- a/drivers/mtd/devices/spear_smi.c +++ b/drivers/mtd/devices/spear_smi.c @@ -937,7 +937,6 @@ static int spear_smi_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct spear_smi_plat_data *pdata = NULL; struct spear_smi *dev; - struct resource *smi_base; int irq, ret = 0; int i; @@ -975,9 +974,7 @@ static int spear_smi_probe(struct platform_device *pdev) goto err; } - smi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - dev->io_base = devm_ioremap_resource(&pdev->dev, smi_base); + dev->io_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dev->io_base)) { ret = PTR_ERR(dev->io_base); goto err; -- GitLab From e1666cfd78222ae145ac260368f29fa443d97b3f Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Fri, 7 Jul 2023 12:06:22 +0800 Subject: [PATCH 0109/3445] mtd: physmap-core: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230707040622.78174-18-frank.li@vivo.com --- drivers/mtd/maps/physmap-core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mtd/maps/physmap-core.c b/drivers/mtd/maps/physmap-core.c index c73854da51363..78710fbc8e7f6 100644 --- a/drivers/mtd/maps/physmap-core.c +++ b/drivers/mtd/maps/physmap-core.c @@ -508,8 +508,7 @@ static int physmap_flash_probe(struct platform_device *dev) for (i = 0; i < info->nmaps; i++) { struct resource *res; - res = platform_get_resource(dev, IORESOURCE_MEM, i); - info->maps[i].virt = devm_ioremap_resource(&dev->dev, res); + info->maps[i].virt = devm_platform_get_and_ioremap_resource(dev, i, &res); if (IS_ERR(info->maps[i].virt)) { err = PTR_ERR(info->maps[i].virt); goto err_out; -- GitLab From 65e02e840847158c7ee48ca8e6e91062b0f78662 Mon Sep 17 00:00:00 2001 From: Minjie Du Date: Thu, 6 Jul 2023 10:27:03 +0800 Subject: [PATCH 0110/3445] RDMA/qedr: Remove a duplicate assignment in irdma_query_ah() Delete a duplicate statement from this function implementation. Fixes: b48c24c2d710 ("RDMA/irdma: Implement device supported verb APIs") Signed-off-by: Minjie Du Acked-by: Alok Prasad Link: https://lore.kernel.org/r/20230706022704.1260-1-duminjie@vivo.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/irdma/verbs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c index 9c4fe4fa90018..a8326a95d186c 100644 --- a/drivers/infiniband/hw/irdma/verbs.c +++ b/drivers/infiniband/hw/irdma/verbs.c @@ -4424,7 +4424,6 @@ static int irdma_query_ah(struct ib_ah *ibah, struct rdma_ah_attr *ah_attr) ah_attr->grh.traffic_class = ah->sc_ah.ah_info.tc_tos; ah_attr->grh.hop_limit = ah->sc_ah.ah_info.hop_ttl; ah_attr->grh.sgid_index = ah->sgid_index; - ah_attr->grh.sgid_index = ah->sgid_index; memcpy(&ah_attr->grh.dgid, &ah->dgid, sizeof(ah_attr->grh.dgid)); } -- GitLab From f877f22ac1e9bf1f9aded3765b0012851e1dc4c5 Mon Sep 17 00:00:00 2001 From: Mustafa Ismail Date: Tue, 11 Jul 2023 12:53:18 -0500 Subject: [PATCH 0111/3445] RDMA/irdma: Implement egress VLAN priority When a VLAN interface is in use, get and use the VLAN egress mapping. Signed-off-by: Mustafa Ismail Signed-off-by: Shiraz Saleem Link: https://lore.kernel.org/r/20230711175318.1301-1-shiraz.saleem@intel.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/irdma/cm.c | 66 +++++++++++++++++++++++++++-- drivers/infiniband/hw/irdma/verbs.c | 45 ++++++++++++++++---- 2 files changed, 99 insertions(+), 12 deletions(-) diff --git a/drivers/infiniband/hw/irdma/cm.c b/drivers/infiniband/hw/irdma/cm.c index 70009b970e08b..6b71b67ce9ff0 100644 --- a/drivers/infiniband/hw/irdma/cm.c +++ b/drivers/infiniband/hw/irdma/cm.c @@ -1555,6 +1555,41 @@ static int irdma_del_multiple_qhash(struct irdma_device *iwdev, return ret; } +static u8 irdma_iw_get_vlan_prio(u32 *loc_addr, u8 prio, bool ipv4) +{ + struct net_device *ndev = NULL; + + rcu_read_lock(); + if (ipv4) { + ndev = ip_dev_find(&init_net, htonl(loc_addr[0])); + } else { + struct net_device *ip_dev; + struct in6_addr laddr6; + + irdma_copy_ip_htonl(laddr6.in6_u.u6_addr32, loc_addr); + + for_each_netdev_rcu (&init_net, ip_dev) { + if (ipv6_chk_addr(&init_net, &laddr6, ip_dev, 1)) { + ndev = ip_dev; + break; + } + } + } + + if (!ndev) + goto done; + if (is_vlan_dev(ndev)) + prio = (vlan_dev_get_egress_qos_mask(ndev, prio) & VLAN_PRIO_MASK) + >> VLAN_PRIO_SHIFT; + if (ipv4) + dev_put(ndev); + +done: + rcu_read_unlock(); + + return prio; +} + /** * irdma_netdev_vlan_ipv6 - Gets the netdev and mac * @addr: local IPv6 address @@ -1667,6 +1702,12 @@ static int irdma_add_mqh_6(struct irdma_device *iwdev, ifp->addr.in6_u.u6_addr32); memcpy(cm_info->loc_addr, child_listen_node->loc_addr, sizeof(cm_info->loc_addr)); + if (!iwdev->vsi.dscp_mode) + cm_info->user_pri = + irdma_iw_get_vlan_prio(child_listen_node->loc_addr, + cm_info->user_pri, + false); + ret = irdma_manage_qhash(iwdev, cm_info, IRDMA_QHASH_TYPE_TCP_SYN, IRDMA_QHASH_MANAGE_TYPE_ADD, @@ -1751,6 +1792,11 @@ static int irdma_add_mqh_4(struct irdma_device *iwdev, ntohl(ifa->ifa_address); memcpy(cm_info->loc_addr, child_listen_node->loc_addr, sizeof(cm_info->loc_addr)); + if (!iwdev->vsi.dscp_mode) + cm_info->user_pri = + irdma_iw_get_vlan_prio(child_listen_node->loc_addr, + cm_info->user_pri, + true); ret = irdma_manage_qhash(iwdev, cm_info, IRDMA_QHASH_TYPE_TCP_SYN, IRDMA_QHASH_MANAGE_TYPE_ADD, @@ -2219,6 +2265,10 @@ irdma_make_cm_node(struct irdma_cm_core *cm_core, struct irdma_device *iwdev, } else { cm_node->tos = max(listener->tos, cm_info->tos); cm_node->user_pri = rt_tos2priority(cm_node->tos); + cm_node->user_pri = + irdma_iw_get_vlan_prio(cm_info->loc_addr, + cm_node->user_pri, + cm_info->ipv4); } ibdev_dbg(&iwdev->ibdev, "DCB: listener: TOS:[%d] UP:[%d]\n", cm_node->tos, @@ -3832,11 +3882,15 @@ int irdma_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) cm_info.cm_id = cm_id; cm_info.qh_qpid = iwdev->vsi.ilq->qp_id; cm_info.tos = cm_id->tos; - if (iwdev->vsi.dscp_mode) + if (iwdev->vsi.dscp_mode) { cm_info.user_pri = iwqp->sc_qp.vsi->dscp_map[irdma_tos2dscp(cm_info.tos)]; - else + } else { cm_info.user_pri = rt_tos2priority(cm_id->tos); + cm_info.user_pri = irdma_iw_get_vlan_prio(cm_info.loc_addr, + cm_info.user_pri, + cm_info.ipv4); + } if (iwqp->sc_qp.dev->ws_add(iwqp->sc_qp.vsi, cm_info.user_pri)) return -ENOMEM; @@ -3980,7 +4034,7 @@ int irdma_create_listen(struct iw_cm_id *cm_id, int backlog) cm_listen_node->tos = cm_id->tos; if (iwdev->vsi.dscp_mode) cm_listen_node->user_pri = - iwdev->vsi.dscp_map[irdma_tos2dscp(cm_id->tos)]; + iwdev->vsi.dscp_map[irdma_tos2dscp(cm_id->tos)]; else cm_listen_node->user_pri = rt_tos2priority(cm_id->tos); cm_info.user_pri = cm_listen_node->user_pri; @@ -3990,6 +4044,12 @@ int irdma_create_listen(struct iw_cm_id *cm_id, int backlog) if (err) goto error; } else { + if (!iwdev->vsi.dscp_mode) + cm_listen_node->user_pri = + irdma_iw_get_vlan_prio(cm_info.loc_addr, + cm_info.user_pri, + cm_info.ipv4); + cm_info.user_pri = cm_listen_node->user_pri; err = irdma_manage_qhash(iwdev, &cm_info, IRDMA_QHASH_TYPE_TCP_SYN, IRDMA_QHASH_MANAGE_TYPE_ADD, diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c index a8326a95d186c..a7b82aea4d08e 100644 --- a/drivers/infiniband/hw/irdma/verbs.c +++ b/drivers/infiniband/hw/irdma/verbs.c @@ -1098,6 +1098,24 @@ static int irdma_query_pkey(struct ib_device *ibdev, u32 port, u16 index, return 0; } +static u8 irdma_roce_get_vlan_prio(const struct ib_gid_attr *attr, u8 prio) +{ + struct net_device *ndev; + + rcu_read_lock(); + ndev = rcu_dereference(attr->ndev); + if (!ndev) + goto exit; + if (is_vlan_dev(ndev)) { + u16 vlan_qos = vlan_dev_get_egress_qos_mask(ndev, prio); + + prio = (vlan_qos & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; + } +exit: + rcu_read_unlock(); + return prio; +} + /** * irdma_modify_qp_roce - modify qp request * @ibqp: qp's pointer for modify @@ -1174,7 +1192,8 @@ int irdma_modify_qp_roce(struct ib_qp *ibqp, struct ib_qp_attr *attr, if (attr_mask & IB_QP_AV) { struct irdma_av *av = &iwqp->roce_ah.av; - const struct ib_gid_attr *sgid_attr; + const struct ib_gid_attr *sgid_attr = + attr->ah_attr.grh.sgid_attr; u16 vlan_id = VLAN_N_VID; u32 local_ip[4]; @@ -1189,17 +1208,22 @@ int irdma_modify_qp_roce(struct ib_qp *ibqp, struct ib_qp_attr *attr, roce_info->dest_qp); irdma_qp_rem_qos(&iwqp->sc_qp); dev->ws_remove(iwqp->sc_qp.vsi, ctx_info->user_pri); - ctx_info->user_pri = rt_tos2priority(udp_info->tos); - iwqp->sc_qp.user_pri = ctx_info->user_pri; - if (dev->ws_add(iwqp->sc_qp.vsi, ctx_info->user_pri)) - return -ENOMEM; - irdma_qp_add_qos(&iwqp->sc_qp); + if (iwqp->sc_qp.vsi->dscp_mode) + ctx_info->user_pri = + iwqp->sc_qp.vsi->dscp_map[irdma_tos2dscp(udp_info->tos)]; + else + ctx_info->user_pri = rt_tos2priority(udp_info->tos); } - sgid_attr = attr->ah_attr.grh.sgid_attr; ret = rdma_read_gid_l2_fields(sgid_attr, &vlan_id, ctx_info->roce_info->mac_addr); if (ret) return ret; + ctx_info->user_pri = irdma_roce_get_vlan_prio(sgid_attr, + ctx_info->user_pri); + if (dev->ws_add(iwqp->sc_qp.vsi, ctx_info->user_pri)) + return -ENOMEM; + iwqp->sc_qp.user_pri = ctx_info->user_pri; + irdma_qp_add_qos(&iwqp->sc_qp); if (vlan_id >= VLAN_N_VID && iwdev->dcb_vlan_mode) vlan_id = 0; @@ -4261,9 +4285,12 @@ static int irdma_setup_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *attr) ah_info->vlan_tag = 0; if (ah_info->vlan_tag < VLAN_N_VID) { + u8 prio = rt_tos2priority(ah_info->tc_tos); + + prio = irdma_roce_get_vlan_prio(sgid_attr, prio); + + ah_info->vlan_tag |= (u16)prio << VLAN_PRIO_SHIFT; ah_info->insert_vlan_tag = true; - ah_info->vlan_tag |= - rt_tos2priority(ah_info->tc_tos) << VLAN_PRIO_SHIFT; } return 0; -- GitLab From 259b4d4c1308a1fa0a671be3ecd8f847c7ce2e95 Mon Sep 17 00:00:00 2001 From: Su Hui Date: Mon, 29 May 2023 09:50:11 +0800 Subject: [PATCH 0112/3445] mtd: devices: docg3: Remove unnecessary (void*) conversions Pointer variables of (void*) type do not require type cast. Signed-off-by: Su Hui Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230529015011.38811-1-suhui@nfschina.com --- drivers/mtd/devices/docg3.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index a7714e3de887f..22e73dd6118b9 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -1599,7 +1599,7 @@ static void doc_unregister_sysfs(struct platform_device *pdev, */ static int flashcontrol_show(struct seq_file *s, void *p) { - struct docg3 *docg3 = (struct docg3 *)s->private; + struct docg3 *docg3 = s->private; u8 fctrl; @@ -1621,7 +1621,7 @@ DEFINE_SHOW_ATTRIBUTE(flashcontrol); static int asic_mode_show(struct seq_file *s, void *p) { - struct docg3 *docg3 = (struct docg3 *)s->private; + struct docg3 *docg3 = s->private; int pctrl, mode; @@ -1658,7 +1658,7 @@ DEFINE_SHOW_ATTRIBUTE(asic_mode); static int device_id_show(struct seq_file *s, void *p) { - struct docg3 *docg3 = (struct docg3 *)s->private; + struct docg3 *docg3 = s->private; int id; mutex_lock(&docg3->cascade->lock); @@ -1672,7 +1672,7 @@ DEFINE_SHOW_ATTRIBUTE(device_id); static int protection_show(struct seq_file *s, void *p) { - struct docg3 *docg3 = (struct docg3 *)s->private; + struct docg3 *docg3 = s->private; int protect, dps0, dps0_low, dps0_high, dps1, dps1_low, dps1_high; mutex_lock(&docg3->cascade->lock); -- GitLab From 7ab04b7cffa5aa646bfaf70d63634767dbf87eba Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 6 Jul 2023 12:21:49 +0100 Subject: [PATCH 0113/3445] dmaengine: sh: rz-dmac: Improve cleanup order in probe()/remove() We usually do cleanup in reverse order of init. Currently, in the case of error, this is not followed in rz_dmac_probe(), and similar case for remove(). This patch improves error handling in probe() and cleanup in reverse order of init in the remove(). Reported-by: Pavel Machek Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Reviewed-by: Pavel Machek Link: https://lore.kernel.org/r/20230706112150.198941-2-biju.das.jz@bp.renesas.com Signed-off-by: Vinod Koul --- drivers/dma/sh/rz-dmac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c index 9479f29692d3e..229f642fde6b2 100644 --- a/drivers/dma/sh/rz-dmac.c +++ b/drivers/dma/sh/rz-dmac.c @@ -947,7 +947,6 @@ static int rz_dmac_probe(struct platform_device *pdev) dma_register_err: of_dma_controller_free(pdev->dev.of_node); err: - reset_control_assert(dmac->rstc); channel_num = i ? i - 1 : 0; for (i = 0; i < channel_num; i++) { struct rz_dmac_chan *channel = &dmac->channels[i]; @@ -958,6 +957,7 @@ err: channel->lmdesc.base_dma); } + reset_control_assert(dmac->rstc); err_pm_runtime_put: pm_runtime_put(&pdev->dev); err_pm_disable: @@ -971,6 +971,8 @@ static int rz_dmac_remove(struct platform_device *pdev) struct rz_dmac *dmac = platform_get_drvdata(pdev); unsigned int i; + dma_async_device_unregister(&dmac->engine); + of_dma_controller_free(pdev->dev.of_node); for (i = 0; i < dmac->n_channels; i++) { struct rz_dmac_chan *channel = &dmac->channels[i]; @@ -979,8 +981,6 @@ static int rz_dmac_remove(struct platform_device *pdev) channel->lmdesc.base, channel->lmdesc.base_dma); } - of_dma_controller_free(pdev->dev.of_node); - dma_async_device_unregister(&dmac->engine); reset_control_assert(dmac->rstc); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); -- GitLab From c6ec8c83a29fb3aec3efa6fabbf5344498f57c7f Mon Sep 17 00:00:00 2001 From: Hien Huynh Date: Thu, 6 Jul 2023 12:21:50 +0100 Subject: [PATCH 0114/3445] dmaengine: sh: rz-dmac: Fix destination and source data size setting Before setting DDS and SDS values, we need to clear its value first otherwise, we get incorrect results when we change/update the DMA bus width several times due to the 'OR' expression. Fixes: 5000d37042a6 ("dmaengine: sh: Add DMAC driver for RZ/G2L SoC") Cc: stable@kernel.org Signed-off-by: Hien Huynh Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230706112150.198941-3-biju.das.jz@bp.renesas.com Signed-off-by: Vinod Koul --- drivers/dma/sh/rz-dmac.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c index 229f642fde6b2..f777addda8bac 100644 --- a/drivers/dma/sh/rz-dmac.c +++ b/drivers/dma/sh/rz-dmac.c @@ -9,6 +9,7 @@ * Copyright 2012 Javier Martin, Vista Silicon */ +#include #include #include #include @@ -145,8 +146,8 @@ struct rz_dmac { #define CHCFG_REQD BIT(3) #define CHCFG_SEL(bits) ((bits) & 0x07) #define CHCFG_MEM_COPY (0x80400008) -#define CHCFG_FILL_DDS(a) (((a) << 16) & GENMASK(19, 16)) -#define CHCFG_FILL_SDS(a) (((a) << 12) & GENMASK(15, 12)) +#define CHCFG_FILL_DDS_MASK GENMASK(19, 16) +#define CHCFG_FILL_SDS_MASK GENMASK(15, 12) #define CHCFG_FILL_TM(a) (((a) & BIT(5)) << 22) #define CHCFG_FILL_AM(a) (((a) & GENMASK(4, 2)) << 6) #define CHCFG_FILL_LVL(a) (((a) & BIT(1)) << 5) @@ -607,13 +608,15 @@ static int rz_dmac_config(struct dma_chan *chan, if (val == CHCFG_DS_INVALID) return -EINVAL; - channel->chcfg |= CHCFG_FILL_DDS(val); + channel->chcfg &= ~CHCFG_FILL_DDS_MASK; + channel->chcfg |= FIELD_PREP(CHCFG_FILL_DDS_MASK, val); val = rz_dmac_ds_to_val_mapping(config->src_addr_width); if (val == CHCFG_DS_INVALID) return -EINVAL; - channel->chcfg |= CHCFG_FILL_SDS(val); + channel->chcfg &= ~CHCFG_FILL_SDS_MASK; + channel->chcfg |= FIELD_PREP(CHCFG_FILL_SDS_MASK, val); return 0; } -- GitLab From e93c47a3ddc6d045fc7dc4bbf1027aad285e1cd5 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 5 Jul 2023 16:18:52 +0800 Subject: [PATCH 0115/3445] dmaengine: qcom: gpi: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230705081856.13734-1-frank.li@vivo.com Signed-off-by: Vinod Koul --- drivers/dma/qcom/gpi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c index 932628b319c81..1c93864e0e4d4 100644 --- a/drivers/dma/qcom/gpi.c +++ b/drivers/dma/qcom/gpi.c @@ -2160,8 +2160,7 @@ static int gpi_probe(struct platform_device *pdev) return -ENOMEM; gpi_dev->dev = &pdev->dev; - gpi_dev->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - gpi_dev->regs = devm_ioremap_resource(gpi_dev->dev, gpi_dev->res); + gpi_dev->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &gpi_dev->res); if (IS_ERR(gpi_dev->regs)) return PTR_ERR(gpi_dev->regs); gpi_dev->ee_base = gpi_dev->regs; -- GitLab From f1e47b8390d4511866a764093c0886a0fa1240ba Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 5 Jul 2023 16:18:53 +0800 Subject: [PATCH 0116/3445] dmaengine: qcom_hidma: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230705081856.13734-2-frank.li@vivo.com Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c index 344525c3a32fa..b5e3633e6a5e1 100644 --- a/drivers/dma/qcom/hidma.c +++ b/drivers/dma/qcom/hidma.c @@ -765,17 +765,15 @@ static int hidma_probe(struct platform_device *pdev) pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); - trca_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - trca = devm_ioremap_resource(&pdev->dev, trca_resource); + trca = devm_platform_get_and_ioremap_resource(pdev, 0, &trca_resource); if (IS_ERR(trca)) { - rc = -ENOMEM; + rc = PTR_ERR(trca); goto bailout; } - evca_resource = platform_get_resource(pdev, IORESOURCE_MEM, 1); - evca = devm_ioremap_resource(&pdev->dev, evca_resource); + evca = devm_platform_get_and_ioremap_resource(pdev, 1, &evca_resource); if (IS_ERR(evca)) { - rc = -ENOMEM; + rc = PTR_ERR(evca); goto bailout; } @@ -785,7 +783,7 @@ static int hidma_probe(struct platform_device *pdev) */ chirq = platform_get_irq(pdev, 0); if (chirq < 0) { - rc = -ENODEV; + rc = chirq; goto bailout; } -- GitLab From 1dedb81c5b8717e2b896b053e540121614555d74 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 5 Jul 2023 16:18:54 +0800 Subject: [PATCH 0117/3445] dmaengine: qcom: hidma_mgmt: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230705081856.13734-3-frank.li@vivo.com Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma_mgmt.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/dma/qcom/hidma_mgmt.c b/drivers/dma/qcom/hidma_mgmt.c index 05e96b31d8716..1d675f31252b8 100644 --- a/drivers/dma/qcom/hidma_mgmt.c +++ b/drivers/dma/qcom/hidma_mgmt.c @@ -176,10 +176,9 @@ static int hidma_mgmt_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - virtaddr = devm_ioremap_resource(&pdev->dev, res); + virtaddr = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(virtaddr)) { - rc = -ENOMEM; + rc = PTR_ERR(virtaddr); goto out; } -- GitLab From 8b229a01a5b846bf7a45c8ef11bc3b81326c9409 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 5 Jul 2023 16:18:55 +0800 Subject: [PATCH 0118/3445] dmaengine: shdmac: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230705081856.13734-4-frank.li@vivo.com Signed-off-by: Vinod Koul --- drivers/dma/sh/shdmac.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/dma/sh/shdmac.c b/drivers/dma/sh/shdmac.c index 5aafe548ca5f3..fb3c56a416d15 100644 --- a/drivers/dma/sh/shdmac.c +++ b/drivers/dma/sh/shdmac.c @@ -678,7 +678,7 @@ static int sh_dmae_probe(struct platform_device *pdev) int err, errirq, i, irq_cnt = 0, irqres = 0, irq_cap = 0; struct sh_dmae_device *shdev; struct dma_device *dma_dev; - struct resource *chan, *dmars, *errirq_res, *chanirq_res; + struct resource *dmars, *errirq_res, *chanirq_res; if (pdev->dev.of_node) pdata = of_device_get_match_data(&pdev->dev); @@ -689,7 +689,6 @@ static int sh_dmae_probe(struct platform_device *pdev) if (!pdata || !pdata->channel_num) return -ENODEV; - chan = platform_get_resource(pdev, IORESOURCE_MEM, 0); /* DMARS area is optional */ dmars = platform_get_resource(pdev, IORESOURCE_MEM, 1); /* @@ -709,7 +708,7 @@ static int sh_dmae_probe(struct platform_device *pdev) * requested with the IRQF_SHARED flag */ errirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!chan || !errirq_res) + if (!errirq_res) return -ENODEV; shdev = devm_kzalloc(&pdev->dev, sizeof(struct sh_dmae_device), @@ -719,7 +718,7 @@ static int sh_dmae_probe(struct platform_device *pdev) dma_dev = &shdev->shdma_dev.dma_dev; - shdev->chan_reg = devm_ioremap_resource(&pdev->dev, chan); + shdev->chan_reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(shdev->chan_reg)) return PTR_ERR(shdev->chan_reg); if (dmars) { -- GitLab From 42c3cdaaacaa2d17e806ab81d7caca148bf32984 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 5 Jul 2023 16:18:56 +0800 Subject: [PATCH 0119/3445] dmaengine: stm32-dma: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Reviewed-by: Amelie Delaunay Tested-by: Amelie Delaunay Link: https://lore.kernel.org/r/20230705081856.13734-5-frank.li@vivo.com Signed-off-by: Vinod Koul --- drivers/dma/stm32-dma.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index 37674029cb427..5c36811aa1342 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -1581,8 +1581,7 @@ static int stm32_dma_probe(struct platform_device *pdev) dd = &dmadev->ddev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dmadev->base = devm_ioremap_resource(&pdev->dev, res); + dmadev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(dmadev->base)) return PTR_ERR(dmadev->base); -- GitLab From 83adc98ec0d8aaa527cac57c9102363a24876783 Mon Sep 17 00:00:00 2001 From: Bhupesh Sharma Date: Fri, 30 Jun 2023 13:52:29 +0530 Subject: [PATCH 0120/3445] dt-bindings: dma: Add support for SM6115 and QCM2290 SoCs Add new compatible for BAM DMA engine version v1.7.4 which is found on Qualcomm SM6115 and QCM2290 SoCs. Since its very similar to v1.7.0 used on SM8150 like SoCs, mark the comptible scheme accordingly. While at it, also update qcom,bam-dma bindings to add comments which describe the BAM DMA versions used in SM8150 and SM8250 SoCs. This provides an easy reference for identifying the actual BAM DMA version available on Qualcomm SoCs. Acked-by: Rob Herring Tested-by: Anders Roxell Tested-by: Linux Kernel Functional Testing Signed-off-by: Bhupesh Sharma Link: https://lore.kernel.org/r/20230630082230.2264698-2-bhupesh.sharma@linaro.org Signed-off-by: Vinod Koul --- .../devicetree/bindings/dma/qcom,bam-dma.yaml | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml b/Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml index f1ddcf672261a..c663b6102f50d 100644 --- a/Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml +++ b/Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml @@ -15,13 +15,19 @@ allOf: properties: compatible: - enum: - # APQ8064, IPQ8064 and MSM8960 - - qcom,bam-v1.3.0 - # MSM8974, APQ8074 and APQ8084 - - qcom,bam-v1.4.0 - # MSM8916 and SDM845 - - qcom,bam-v1.7.0 + oneOf: + - enum: + # APQ8064, IPQ8064 and MSM8960 + - qcom,bam-v1.3.0 + # MSM8974, APQ8074 and APQ8084 + - qcom,bam-v1.4.0 + # MSM8916, SDM630 + - qcom,bam-v1.7.0 + - items: + - enum: + # SDM845, SM6115, SM8150, SM8250 and QCM2290 + - qcom,bam-v1.7.4 + - const: qcom,bam-v1.7.0 clocks: maxItems: 1 -- GitLab From fbac8ceb441508a0100888fd62f98c32a1d9f506 Mon Sep 17 00:00:00 2001 From: Bhupesh Sharma Date: Fri, 30 Jun 2023 13:52:30 +0530 Subject: [PATCH 0121/3445] dt-bindings: dma: Increase iommu maxItems for BAM DMA Since SM8250 BAM DMA engine supports six iommu entries, increase the maxItems in the iommu property section, without which 'dtbs_check' would throw errors. Acked-by: Krzysztof Kozlowski Tested-by: Anders Roxell Tested-by: Linux Kernel Functional Testing Signed-off-by: Bhupesh Sharma Link: https://lore.kernel.org/r/20230630082230.2264698-3-bhupesh.sharma@linaro.org Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml b/Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml index c663b6102f50d..6433f2892ae4d 100644 --- a/Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml +++ b/Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml @@ -44,7 +44,7 @@ properties: iommus: minItems: 1 - maxItems: 4 + maxItems: 6 num-channels: $ref: /schemas/types.yaml#/definitions/uint32 -- GitLab From dfcfe386d025fe94ee4373777c6b84eba8988a38 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 17 Jun 2023 15:36:15 +0200 Subject: [PATCH 0122/3445] dt-bindings: dma: convert bcm2835-dma bindings to YAML Convert the DT binding document for bcm2835-dma from .txt to YAML. Signed-off-by: Stefan Wahren Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230617133620.53129-3-stefan.wahren@i2se.com Signed-off-by: Vinod Koul --- .../bindings/dma/brcm,bcm2835-dma.txt | 83 -------------- .../bindings/dma/brcm,bcm2835-dma.yaml | 102 ++++++++++++++++++ 2 files changed, 102 insertions(+), 83 deletions(-) delete mode 100644 Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt create mode 100644 Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.yaml diff --git a/Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt b/Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt deleted file mode 100644 index b6a8cc0978cd5..0000000000000 --- a/Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt +++ /dev/null @@ -1,83 +0,0 @@ -* BCM2835 DMA controller - -The BCM2835 DMA controller has 16 channels in total. -Only the lower 13 channels have an associated IRQ. -Some arbitrary channels are used by the firmware -(1,3,6,7 in the current firmware version). -The channels 0,2 and 3 have special functionality -and should not be used by the driver. - -Required properties: -- compatible: Should be "brcm,bcm2835-dma". -- reg: Should contain DMA registers location and length. -- interrupts: Should contain the DMA interrupts associated - to the DMA channels in ascending order. -- interrupt-names: Should contain the names of the interrupt - in the form "dmaXX". - Use "dma-shared-all" for the common interrupt line - that is shared by all dma channels. -- #dma-cells: Must be <1>, the cell in the dmas property of the - client device represents the DREQ number. -- brcm,dma-channel-mask: Bit mask representing the channels - not used by the firmware in ascending order, - i.e. first channel corresponds to LSB. - -Example: - -dma: dma@7e007000 { - compatible = "brcm,bcm2835-dma"; - reg = <0x7e007000 0xf00>; - interrupts = <1 16>, - <1 17>, - <1 18>, - <1 19>, - <1 20>, - <1 21>, - <1 22>, - <1 23>, - <1 24>, - <1 25>, - <1 26>, - /* dma channel 11-14 share one irq */ - <1 27>, - <1 27>, - <1 27>, - <1 27>, - /* unused shared irq for all channels */ - <1 28>; - interrupt-names = "dma0", - "dma1", - "dma2", - "dma3", - "dma4", - "dma5", - "dma6", - "dma7", - "dma8", - "dma9", - "dma10", - "dma11", - "dma12", - "dma13", - "dma14", - "dma-shared-all"; - - #dma-cells = <1>; - brcm,dma-channel-mask = <0x7f35>; -}; - - -DMA clients connected to the BCM2835 DMA controller must use the format -described in the dma.txt file, using a two-cell specifier for each channel. - -Example: - -bcm2835_i2s: i2s@7e203000 { - compatible = "brcm,bcm2835-i2s"; - reg = < 0x7e203000 0x24>; - clocks = <&clocks BCM2835_CLOCK_PCM>; - - dmas = <&dma 2>, - <&dma 3>; - dma-names = "tx", "rx"; -}; diff --git a/Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.yaml b/Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.yaml new file mode 100644 index 0000000000000..c9b9a5490826c --- /dev/null +++ b/Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.yaml @@ -0,0 +1,102 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dma/brcm,bcm2835-dma.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: BCM2835 DMA controller + +maintainers: + - Nicolas Saenz Julienne + +description: + The BCM2835 DMA controller has 16 channels in total. Only the lower + 13 channels have an associated IRQ. Some arbitrary channels are used by the + VideoCore firmware (1,3,6,7 in the current firmware version). The channels + 0, 2 and 3 have special functionality and should not be used by the driver. + +allOf: + - $ref: dma-controller.yaml# + +properties: + compatible: + const: brcm,bcm2835-dma + + reg: + maxItems: 1 + + interrupts: + description: + Should contain the DMA interrupts associated to the DMA channels in + ascending order. + minItems: 1 + maxItems: 16 + + interrupt-names: + minItems: 1 + maxItems: 16 + + '#dma-cells': + description: The single cell represents the DREQ number. + const: 1 + + brcm,dma-channel-mask: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Bitmask of available DMA channels in ascending order that are + not reserved by firmware and are available to the + kernel. i.e. first channel corresponds to LSB. + +unevaluatedProperties: false + +required: + - compatible + - reg + - interrupts + - "#dma-cells" + - brcm,dma-channel-mask + +examples: + - | + dma-controller@7e007000 { + compatible = "brcm,bcm2835-dma"; + reg = <0x7e007000 0xf00>; + interrupts = <1 16>, + <1 17>, + <1 18>, + <1 19>, + <1 20>, + <1 21>, + <1 22>, + <1 23>, + <1 24>, + <1 25>, + <1 26>, + /* dma channel 11-14 share one irq */ + <1 27>, + <1 27>, + <1 27>, + <1 27>, + /* unused shared irq for all channels */ + <1 28>; + interrupt-names = "dma0", + "dma1", + "dma2", + "dma3", + "dma4", + "dma5", + "dma6", + "dma7", + "dma8", + "dma9", + "dma10", + "dma11", + "dma12", + "dma13", + "dma14", + "dma-shared-all"; + #dma-cells = <1>; + brcm,dma-channel-mask = <0x7f35>; + }; + +... -- GitLab From 3533913ae5390f02ba3db989ad3bfed23f436d57 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 26 Jun 2023 16:56:45 +0200 Subject: [PATCH 0123/3445] dt-bindings: dma: qcom,bam: require one of control methods The BAM DMA resources can be controlled remotely (e.g. by trusted environment; needs qcom,powered-remotely or qcom,controlled-remotely properties) or locally. In the latter case we need to provide its clock. Require one of methods of such control to properly validate DTS. Signed-off-by: Krzysztof Kozlowski Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20230626145645.646136-1-krzysztof.kozlowski@linaro.org Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml b/Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml index 6433f2892ae4d..20fc8c16ded82 100644 --- a/Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml +++ b/Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml @@ -87,6 +87,15 @@ required: - qcom,ee - reg +anyOf: + - required: + - qcom,powered-remotely + - required: + - qcom,controlled-remotely + - required: + - clocks + - clock-names + additionalProperties: false examples: -- GitLab From ecc3cfc31f33c88cb9fa8fd1fcfc8a86e4b7b18b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 22 Jun 2023 09:51:50 +0200 Subject: [PATCH 0124/3445] dmaengine: mediatek: drop bogus pm_runtime_set_active() The runtime PM state must be updated while runtime PM is disabled for the change to take effect. Drop the bogus pm_runtime_set_active() which left the PM state set to suspended (as it should be or the clock would not be enabled when the device is resumed). Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20230622075150.885-1-johan+linaro@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/mediatek/mtk-uart-apdma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/dma/mediatek/mtk-uart-apdma.c b/drivers/dma/mediatek/mtk-uart-apdma.c index a1517ef1f4a01..92864c9371a31 100644 --- a/drivers/dma/mediatek/mtk-uart-apdma.c +++ b/drivers/dma/mediatek/mtk-uart-apdma.c @@ -551,7 +551,6 @@ static int mtk_uart_apdma_probe(struct platform_device *pdev) } pm_runtime_enable(&pdev->dev); - pm_runtime_set_active(&pdev->dev); rc = dma_async_device_register(&mtkd->ddev); if (rc) -- GitLab From 50c5e6f41d5ad7c731c31135a30d0e4f0e4fea26 Mon Sep 17 00:00:00 2001 From: Rex Zhang Date: Wed, 14 Jun 2023 14:27:06 +0800 Subject: [PATCH 0125/3445] dmaengine: idxd: Modify the dependence of attribute pasid_enabled Kernel PASID and user PASID are separately enabled. User needs to know the user PASID enabling status to decide how to use IDXD device in user space. This is done via the attribute /sys/bus/dsa/devices/dsa0/pasid_enabled. It's unnecessary for user to know the kernel PASID enabling status because user won't use the kernel PASID. But instead of showing the user PASID enabling status, the attribute shows the kernel PASID enabling status. Fix the issue by showing the user PASID enabling status in the attribute. Fixes: 42a1b73852c4 ("dmaengine: idxd: Separate user and kernel pasid enabling") Signed-off-by: Rex Zhang Acked-by: Fenghua Yu Acked-by: Dave Jiang Link: https://lore.kernel.org/r/20230614062706.1743078-1-rex.zhang@intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index 293739ac55969..b6a0a12412afd 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -1480,7 +1480,7 @@ static ssize_t pasid_enabled_show(struct device *dev, { struct idxd_device *idxd = confdev_to_idxd(dev); - return sysfs_emit(buf, "%u\n", device_pasid_enabled(idxd)); + return sysfs_emit(buf, "%u\n", device_user_pasid_enabled(idxd)); } static DEVICE_ATTR_RO(pasid_enabled); -- GitLab From b449c3f94dbf26a8c2c5427e16b631273ed81d3b Mon Sep 17 00:00:00 2001 From: Rex Zhang Date: Wed, 14 Jun 2023 14:28:23 +0800 Subject: [PATCH 0126/3445] dmaengine: idxd: Modify ABI documentation for attribute pasid_enabled Modify the sysfs attribute description in ABI/stable documentation for the attribute /sys/bus/dsa/devices/dsa0/pasid_enabled. Signed-off-by: Rex Zhang Acked-by: Fenghua Yu Acked-by: Dave Jiang Link: https://lore.kernel.org/r/20230614062823.1743180-1-rex.zhang@intel.com Signed-off-by: Vinod Koul --- Documentation/ABI/stable/sysfs-driver-dma-idxd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/ABI/stable/sysfs-driver-dma-idxd b/Documentation/ABI/stable/sysfs-driver-dma-idxd index 534b7a3d59fc5..825e619250bf2 100644 --- a/Documentation/ABI/stable/sysfs-driver-dma-idxd +++ b/Documentation/ABI/stable/sysfs-driver-dma-idxd @@ -84,7 +84,7 @@ What: /sys/bus/dsa/devices/dsa/pasid_enabled Date: Oct 27, 2020 KernelVersion: 5.11.0 Contact: dmaengine@vger.kernel.org -Description: To indicate if PASID (process address space identifier) is +Description: To indicate if user PASID (process address space identifier) is enabled or not for this device. What: /sys/bus/dsa/devices/dsa/state -- GitLab From 4ca95a5b220c901f9c2402532ef78bf5aaf7d35d Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 28 May 2023 16:11:54 +0200 Subject: [PATCH 0127/3445] dmaengine: idxd: No need to clear memory after a dma_alloc_coherent() call dma_alloc_coherent() already clear the allocated memory, there is no need to explicitly call memset(). Signed-off-by: Christophe JAILLET Acked-by: Fenghua Yu Acked-by: Dave Jiang Link: https://lore.kernel.org/r/f44be04317387f8936d31d5470963541615f30ef.1685283065.git.christophe.jaillet@wanadoo.fr Signed-off-by: Vinod Koul --- drivers/dma/idxd/device.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index 5abbcc61c5288..7c74bc60f5828 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -786,8 +786,6 @@ static int idxd_device_evl_setup(struct idxd_device *idxd) goto err_alloc; } - memset(addr, 0, size); - spin_lock(&evl->lock); evl->log = addr; evl->dma = dma_addr; -- GitLab From 1b13e52c0c76097fde35d3283e8105545d34b80b Mon Sep 17 00:00:00 2001 From: Zong Li Date: Wed, 31 May 2023 09:01:41 +0000 Subject: [PATCH 0128/3445] dmaengine: xilinx: dma: remove arch dependency As following patches, xilinx dma is also now architecture agnostic, and it can be compiled for several architectures. We have verified the CDMA on RISC-V platform, let's remove the ARCH dependency list instead of adding new ARCH. To avoid breaking the s390 build, add a dependency on HAS_IOMEM. 'e8b6c54f6d57 ("net: xilinx: temac: Relax Kconfig dependencies")' 'd7eaf962a90b ("net: axienet: In kconfig remove arch dependency for axi_emac")' Signed-off-by: Zong Li Acked-by: Palmer Dabbelt Suggested-by: Radhey Shyam Pandey Reported-by: kernel test robot Link: https://lore.kernel.org/r/20230531090141.23546-1-zong.li@sifive.com Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 644c188d6a110..0f9832f0ef586 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -697,7 +697,7 @@ config XGENE_DMA config XILINX_DMA tristate "Xilinx AXI DMAS Engine" - depends on (ARCH_ZYNQ || MICROBLAZE || ARM64) + depends on HAS_IOMEM select DMA_ENGINE help Enable support for Xilinx AXI VDMA Soft IP. -- GitLab From 14626246efb529ebe04812cb4cc08f78be12be9a Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 5 Jul 2023 17:01:23 +0800 Subject: [PATCH 0129/3445] phy: marvell: phy-mvebu-cp110-comphy: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230705090126.26854-1-frank.li@vivo.com Signed-off-by: Vinod Koul --- drivers/phy/marvell/phy-mvebu-cp110-comphy.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/phy/marvell/phy-mvebu-cp110-comphy.c b/drivers/phy/marvell/phy-mvebu-cp110-comphy.c index 34672e868a1e1..ddaddb3c498fd 100644 --- a/drivers/phy/marvell/phy-mvebu-cp110-comphy.c +++ b/drivers/phy/marvell/phy-mvebu-cp110-comphy.c @@ -1011,8 +1011,7 @@ static int mvebu_comphy_probe(struct platform_device *pdev) "marvell,system-controller"); if (IS_ERR(priv->regmap)) return PTR_ERR(priv->regmap); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->base = devm_ioremap_resource(&pdev->dev, res); + priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(priv->base)) return PTR_ERR(priv->base); -- GitLab From 1f8fe326015ff5a3d3b8c3666aa2bb607e7538d1 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 5 Jul 2023 17:01:24 +0800 Subject: [PATCH 0130/3445] phy: rockchip: phy-rockchip-typec: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230705090126.26854-2-frank.li@vivo.com Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-typec.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 8b1667be4915d..4efcb78b0ab18 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -1116,8 +1116,7 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev) return -EINVAL; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - tcphy->base = devm_ioremap_resource(dev, res); + tcphy->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(tcphy->base)) return PTR_ERR(tcphy->base); -- GitLab From d746f127ea5b1d631d48977d1e599c312cbb05c2 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 5 Jul 2023 17:01:25 +0800 Subject: [PATCH 0131/3445] phy: renesas: r8a779f0-ether-serdes: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230705090126.26854-3-frank.li@vivo.com Signed-off-by: Vinod Koul --- drivers/phy/renesas/r8a779f0-ether-serdes.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/phy/renesas/r8a779f0-ether-serdes.c b/drivers/phy/renesas/r8a779f0-ether-serdes.c index 55b7bdfc10d30..67f4c6f8ff91b 100644 --- a/drivers/phy/renesas/r8a779f0-ether-serdes.c +++ b/drivers/phy/renesas/r8a779f0-ether-serdes.c @@ -339,22 +339,15 @@ static int r8a779f0_eth_serdes_probe(struct platform_device *pdev) { struct r8a779f0_eth_serdes_drv_data *dd; struct phy_provider *provider; - struct resource *res; int i; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "invalid resource\n"); - return -EINVAL; - } - dd = devm_kzalloc(&pdev->dev, sizeof(*dd), GFP_KERNEL); if (!dd) return -ENOMEM; platform_set_drvdata(pdev, dd); dd->pdev = pdev; - dd->addr = devm_ioremap_resource(&pdev->dev, res); + dd->addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dd->addr)) return PTR_ERR(dd->addr); -- GitLab From 16e0f0ea7f464cfc04996cf5dee879dfb856bc9a Mon Sep 17 00:00:00 2001 From: Swapnil Jakhade Date: Tue, 30 May 2023 16:38:52 +0200 Subject: [PATCH 0132/3445] phy: cadence-torrent: Add single link USXGMII configuration for 156.25MHz refclk Add register sequences for single link USXGMII configuration supporting 156.25MHz reference clock frequency. Signed-off-by: Swapnil Jakhade Reviewed-by: Roger Quadros Link: https://lore.kernel.org/r/20230530143853.26571-2-sjakhade@cadence.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-torrent.c | 233 +++++++++++++++++++++- 1 file changed, 228 insertions(+), 5 deletions(-) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index 37b6b5c05be85..4b027e23aeb36 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -27,13 +27,14 @@ #define REF_CLK_19_2MHZ 19200000 #define REF_CLK_25MHZ 25000000 #define REF_CLK_100MHZ 100000000 +#define REF_CLK_156_25MHZ 156250000 #define MAX_NUM_LANES 4 #define DEFAULT_MAX_BIT_RATE 8100 /* in Mbps */ #define NUM_SSC_MODE 3 -#define NUM_REF_CLK 3 -#define NUM_PHY_TYPE 6 +#define NUM_REF_CLK 4 +#define NUM_PHY_TYPE 7 #define POLL_TIMEOUT_US 5000 #define PLL_LOCK_TIMEOUT 100000 @@ -106,6 +107,7 @@ #define CMN_PLL0_HIGH_THR_M0 0x0093U #define CMN_PLL0_DSM_DIAG_M0 0x0094U #define CMN_PLL0_DSM_FBH_OVRD_M0 0x0095U +#define CMN_PLL0_DSM_FBL_OVRD_M0 0x0096U #define CMN_PLL0_SS_CTRL1_M0 0x0098U #define CMN_PLL0_SS_CTRL2_M0 0x0099U #define CMN_PLL0_SS_CTRL3_M0 0x009AU @@ -196,6 +198,10 @@ #define RX_PSC_A2 0x0002U #define RX_PSC_A3 0x0003U #define RX_PSC_CAL 0x0006U +#define RX_SDCAL0_INIT_TMR 0x0044U +#define RX_SDCAL0_ITER_TMR 0x0045U +#define RX_SDCAL1_INIT_TMR 0x004CU +#define RX_SDCAL1_ITER_TMR 0x004DU #define RX_CDRLF_CNFG 0x0080U #define RX_CDRLF_CNFG3 0x0082U #define RX_SIGDET_HL_FILT_TMR 0x0090U @@ -294,12 +300,14 @@ enum cdns_torrent_phy_type { TYPE_SGMII, TYPE_QSGMII, TYPE_USB, + TYPE_USXGMII, }; enum cdns_torrent_ref_clk { CLK_19_2_MHZ, CLK_25_MHZ, - CLK_100_MHZ + CLK_100_MHZ, + CLK_156_25_MHZ }; enum cdns_torrent_ssc_mode { @@ -403,6 +411,8 @@ struct cdns_torrent_data { [NUM_SSC_MODE]; struct cdns_torrent_vals *pcs_cmn_vals[NUM_PHY_TYPE][NUM_PHY_TYPE] [NUM_SSC_MODE]; + struct cdns_torrent_vals *phy_pma_cmn_vals[NUM_PHY_TYPE][NUM_PHY_TYPE] + [NUM_SSC_MODE]; struct cdns_torrent_vals *cmn_vals[NUM_REF_CLK][NUM_PHY_TYPE] [NUM_PHY_TYPE][NUM_SSC_MODE]; struct cdns_torrent_vals *tx_ln_vals[NUM_REF_CLK][NUM_PHY_TYPE] @@ -644,6 +654,8 @@ static const char *cdns_torrent_get_phy_type(enum cdns_torrent_phy_type phy_type return "QSGMII"; case TYPE_USB: return "USB"; + case TYPE_USXGMII: + return "USXGMII"; default: return "None"; } @@ -2244,6 +2256,7 @@ static int cdns_torrent_phy_init(struct phy *phy) struct cdns_torrent_inst *inst = phy_get_drvdata(phy); enum cdns_torrent_phy_type phy_type = inst->phy_type; enum cdns_torrent_ssc_mode ssc = inst->ssc_mode; + struct cdns_torrent_vals *phy_pma_cmn_vals; struct cdns_torrent_vals *pcs_cmn_vals; struct cdns_reg_pairs *reg_pairs; struct regmap *regmap; @@ -2258,9 +2271,9 @@ static int cdns_torrent_phy_init(struct phy *phy) /** * Spread spectrum generation is not required or supported - * for SGMII/QSGMII + * for SGMII/QSGMII/USXGMII */ - if (phy_type == TYPE_SGMII || phy_type == TYPE_QSGMII) + if (phy_type == TYPE_SGMII || phy_type == TYPE_QSGMII || phy_type == TYPE_USXGMII) ssc = NO_SSC; /* PHY configuration specific registers for single link */ @@ -2304,6 +2317,17 @@ static int cdns_torrent_phy_init(struct phy *phy) reg_pairs[i].val); } + /* PHY PMA common registers configurations */ + phy_pma_cmn_vals = init_data->phy_pma_cmn_vals[phy_type][TYPE_NONE][ssc]; + if (phy_pma_cmn_vals) { + reg_pairs = phy_pma_cmn_vals->reg_pairs; + num_regs = phy_pma_cmn_vals->num_regs; + regmap = cdns_phy->regmap_phy_pma_common_cdb; + for (i = 0; i < num_regs; i++) + regmap_write(regmap, reg_pairs[i].off, + reg_pairs[i].val); + } + /* PMA common registers configurations */ cmn_vals = init_data->cmn_vals[ref_clk][phy_type][TYPE_NONE][ssc]; if (cmn_vals) { @@ -2617,6 +2641,9 @@ static int cdns_torrent_clk(struct cdns_torrent_phy *cdns_phy) case REF_CLK_100MHZ: cdns_phy->ref_clk_rate = CLK_100_MHZ; break; + case REF_CLK_156_25MHZ: + cdns_phy->ref_clk_rate = CLK_156_25_MHZ; + break; default: dev_err(cdns_phy->dev, "Invalid Ref Clock Rate\n"); clk_disable_unprepare(cdns_phy->clk); @@ -2736,6 +2763,9 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev) case PHY_TYPE_USB3: cdns_phy->phys[node].phy_type = TYPE_USB; break; + case PHY_TYPE_USXGMII: + cdns_phy->phys[node].phy_type = TYPE_USXGMII; + break; default: dev_err(dev, "Unsupported protocol\n"); ret = -EINVAL; @@ -2929,6 +2959,123 @@ static struct cdns_torrent_vals dp_usb_xcvr_diag_ln_vals = { .num_regs = ARRAY_SIZE(dp_usb_xcvr_diag_ln_regs), }; +/* TI USXGMII configuration: Enable cmn_refclk_rcv_out_en */ +static struct cdns_reg_pairs ti_usxgmii_phy_pma_cmn_regs[] = { + {0x0040, PHY_PMA_CMN_CTRL1}, +}; + +static struct cdns_torrent_vals ti_usxgmii_phy_pma_cmn_vals = { + .reg_pairs = ti_usxgmii_phy_pma_cmn_regs, + .num_regs = ARRAY_SIZE(ti_usxgmii_phy_pma_cmn_regs), +}; + +/* Single USXGMII link configuration */ +static struct cdns_reg_pairs sl_usxgmii_link_cmn_regs[] = { + {0x0000, PHY_PLL_CFG}, + {0x0400, CMN_PDIAG_PLL0_CLK_SEL_M0} +}; + +static struct cdns_reg_pairs sl_usxgmii_xcvr_diag_ln_regs[] = { + {0x0000, XCVR_DIAG_HSCLK_SEL}, + {0x0001, XCVR_DIAG_HSCLK_DIV}, + {0x0001, XCVR_DIAG_PLLDRC_CTRL} +}; + +static struct cdns_torrent_vals sl_usxgmii_link_cmn_vals = { + .reg_pairs = sl_usxgmii_link_cmn_regs, + .num_regs = ARRAY_SIZE(sl_usxgmii_link_cmn_regs), +}; + +static struct cdns_torrent_vals sl_usxgmii_xcvr_diag_ln_vals = { + .reg_pairs = sl_usxgmii_xcvr_diag_ln_regs, + .num_regs = ARRAY_SIZE(sl_usxgmii_xcvr_diag_ln_regs), +}; + +/* Single link USXGMII, 156.25 MHz Ref clk, no SSC */ +static struct cdns_reg_pairs sl_usxgmii_156_25_no_ssc_cmn_regs[] = { + {0x0014, CMN_SSM_BIAS_TMR}, + {0x0028, CMN_PLLSM0_PLLPRE_TMR}, + {0x00A4, CMN_PLLSM0_PLLLOCK_TMR}, + {0x0028, CMN_PLLSM1_PLLPRE_TMR}, + {0x00A4, CMN_PLLSM1_PLLLOCK_TMR}, + {0x0062, CMN_BGCAL_INIT_TMR}, + {0x0062, CMN_BGCAL_ITER_TMR}, + {0x0014, CMN_IBCAL_INIT_TMR}, + {0x0018, CMN_TXPUCAL_INIT_TMR}, + {0x0005, CMN_TXPUCAL_ITER_TMR}, + {0x0018, CMN_TXPDCAL_INIT_TMR}, + {0x0005, CMN_TXPDCAL_ITER_TMR}, + {0x024A, CMN_RXCAL_INIT_TMR}, + {0x0005, CMN_RXCAL_ITER_TMR}, + {0x000B, CMN_SD_CAL_REFTIM_START}, + {0x0132, CMN_SD_CAL_PLLCNT_START}, + {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, + {0x0014, CMN_PLL0_DSM_FBH_OVRD_M0}, + {0x0014, CMN_PLL1_DSM_FBH_OVRD_M0}, + {0x0005, CMN_PLL0_DSM_FBL_OVRD_M0}, + {0x0005, CMN_PLL1_DSM_FBL_OVRD_M0}, + {0x061B, CMN_PLL0_VCOCAL_INIT_TMR}, + {0x061B, CMN_PLL1_VCOCAL_INIT_TMR}, + {0x0019, CMN_PLL0_VCOCAL_ITER_TMR}, + {0x0019, CMN_PLL1_VCOCAL_ITER_TMR}, + {0x1354, CMN_PLL0_VCOCAL_REFTIM_START}, + {0x1354, CMN_PLL1_VCOCAL_REFTIM_START}, + {0x1354, CMN_PLL0_VCOCAL_PLLCNT_START}, + {0x1354, CMN_PLL1_VCOCAL_PLLCNT_START}, + {0x0003, CMN_PLL0_VCOCAL_TCTRL}, + {0x0003, CMN_PLL1_VCOCAL_TCTRL}, + {0x0138, CMN_PLL0_LOCK_REFCNT_START}, + {0x0138, CMN_PLL1_LOCK_REFCNT_START}, + {0x0138, CMN_PLL0_LOCK_PLLCNT_START}, + {0x0138, CMN_PLL1_LOCK_PLLCNT_START} +}; + +static struct cdns_reg_pairs usxgmii_156_25_no_ssc_tx_ln_regs[] = { + {0x07A2, TX_RCVDET_ST_TMR}, + {0x00F3, TX_PSC_A0}, + {0x04A2, TX_PSC_A2}, + {0x04A2, TX_PSC_A3}, + {0x0000, TX_TXCC_CPOST_MULT_00}, + {0x0000, XCVR_DIAG_PSC_OVRD} +}; + +static struct cdns_reg_pairs usxgmii_156_25_no_ssc_rx_ln_regs[] = { + {0x0014, RX_SDCAL0_INIT_TMR}, + {0x0062, RX_SDCAL0_ITER_TMR}, + {0x0014, RX_SDCAL1_INIT_TMR}, + {0x0062, RX_SDCAL1_ITER_TMR}, + {0x091D, RX_PSC_A0}, + {0x0900, RX_PSC_A2}, + {0x0100, RX_PSC_A3}, + {0x0030, RX_REE_SMGM_CTRL1}, + {0x03C7, RX_REE_GCSM1_EQENM_PH1}, + {0x01C7, RX_REE_GCSM1_EQENM_PH2}, + {0x0000, RX_DIAG_DFE_CTRL}, + {0x0019, RX_REE_TAP1_CLIP}, + {0x0019, RX_REE_TAP2TON_CLIP}, + {0x00B9, RX_DIAG_NQST_CTRL}, + {0x0C21, RX_DIAG_DFE_AMP_TUNE_2}, + {0x0002, RX_DIAG_DFE_AMP_TUNE_3}, + {0x0033, RX_DIAG_PI_RATE}, + {0x0001, RX_DIAG_ACYA}, + {0x018C, RX_CDRLF_CNFG} +}; + +static struct cdns_torrent_vals sl_usxgmii_156_25_no_ssc_cmn_vals = { + .reg_pairs = sl_usxgmii_156_25_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(sl_usxgmii_156_25_no_ssc_cmn_regs), +}; + +static struct cdns_torrent_vals usxgmii_156_25_no_ssc_tx_ln_vals = { + .reg_pairs = usxgmii_156_25_no_ssc_tx_ln_regs, + .num_regs = ARRAY_SIZE(usxgmii_156_25_no_ssc_tx_ln_regs), +}; + +static struct cdns_torrent_vals usxgmii_156_25_no_ssc_rx_ln_vals = { + .reg_pairs = usxgmii_156_25_no_ssc_rx_ln_regs, + .num_regs = ARRAY_SIZE(usxgmii_156_25_no_ssc_rx_ln_regs), +}; + /* PCIe and DP link configuration */ static struct cdns_reg_pairs pcie_dp_link_cmn_regs[] = { {0x0003, PHY_PLL_CFG}, @@ -4029,6 +4176,11 @@ static const struct cdns_torrent_data cdns_map_torrent = { [NO_SSC] = &usb_dp_link_cmn_vals, }, }, + [TYPE_USXGMII] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_usxgmii_link_cmn_vals, + }, + }, }, .xcvr_diag_vals = { [TYPE_DP] = { @@ -4122,6 +4274,11 @@ static const struct cdns_torrent_data cdns_map_torrent = { [NO_SSC] = &usb_dp_xcvr_diag_ln_vals, }, }, + [TYPE_USXGMII] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_usxgmii_xcvr_diag_ln_vals, + }, + }, }, .pcs_cmn_vals = { [TYPE_USB] = { @@ -4150,6 +4307,13 @@ static const struct cdns_torrent_data cdns_map_torrent = { }, }, }, + .phy_pma_cmn_vals = { + [TYPE_USXGMII] = { + [TYPE_NONE] = { + [NO_SSC] = NULL, + }, + }, + }, .cmn_vals = { [CLK_19_2_MHZ] = { [TYPE_DP] = { @@ -4258,6 +4422,13 @@ static const struct cdns_torrent_data cdns_map_torrent = { }, }, }, + [CLK_156_25_MHZ] = { + [TYPE_USXGMII] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_usxgmii_156_25_no_ssc_cmn_vals, + }, + }, + }, }, .tx_ln_vals = { [CLK_19_2_MHZ] = { @@ -4367,6 +4538,13 @@ static const struct cdns_torrent_data cdns_map_torrent = { }, }, }, + [CLK_156_25_MHZ] = { + [TYPE_USXGMII] = { + [TYPE_NONE] = { + [NO_SSC] = &usxgmii_156_25_no_ssc_tx_ln_vals, + }, + }, + }, }, .rx_ln_vals = { [CLK_19_2_MHZ] = { @@ -4476,6 +4654,13 @@ static const struct cdns_torrent_data cdns_map_torrent = { }, }, }, + [CLK_156_25_MHZ] = { + [TYPE_USXGMII] = { + [TYPE_NONE] = { + [NO_SSC] = &usxgmii_156_25_no_ssc_rx_ln_vals, + }, + }, + }, }, }; @@ -4574,6 +4759,11 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { [NO_SSC] = &usb_dp_link_cmn_vals, }, }, + [TYPE_USXGMII] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_usxgmii_link_cmn_vals, + }, + }, }, .xcvr_diag_vals = { [TYPE_DP] = { @@ -4667,6 +4857,11 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { [NO_SSC] = &usb_dp_xcvr_diag_ln_vals, }, }, + [TYPE_USXGMII] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_usxgmii_xcvr_diag_ln_vals, + }, + }, }, .pcs_cmn_vals = { [TYPE_USB] = { @@ -4695,6 +4890,13 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, }, }, + .phy_pma_cmn_vals = { + [TYPE_USXGMII] = { + [TYPE_NONE] = { + [NO_SSC] = &ti_usxgmii_phy_pma_cmn_vals, + }, + }, + }, .cmn_vals = { [CLK_19_2_MHZ] = { [TYPE_DP] = { @@ -4803,6 +5005,13 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, }, }, + [CLK_156_25_MHZ] = { + [TYPE_USXGMII] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_usxgmii_156_25_no_ssc_cmn_vals, + }, + }, + }, }, .tx_ln_vals = { [CLK_19_2_MHZ] = { @@ -4912,6 +5121,13 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, }, }, + [CLK_156_25_MHZ] = { + [TYPE_USXGMII] = { + [TYPE_NONE] = { + [NO_SSC] = &usxgmii_156_25_no_ssc_tx_ln_vals, + }, + }, + }, }, .rx_ln_vals = { [CLK_19_2_MHZ] = { @@ -5021,6 +5237,13 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, }, }, + [CLK_156_25_MHZ] = { + [TYPE_USXGMII] = { + [TYPE_NONE] = { + [NO_SSC] = &usxgmii_156_25_no_ssc_rx_ln_vals, + }, + }, + }, }, }; -- GitLab From ebd05f90bfef856e10fbd5da2bfb9357676a24e6 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Tue, 30 May 2023 16:38:53 +0200 Subject: [PATCH 0133/3445] phy: cadence-torrent: Use key:value pair table for all settings Instead of a 3D matrix use a key:value pair table for link_cmn_vals, xcvr_diag_vals, pcs_cmn_vals, phy_pma_cmn_vals, cmn_vals, tx_ln_vals and rx_ln_vals. This makes it scaleable for multiple reference clocks. Wherever both CDNS and TI use the same settings, reuse the same data. Introduce CLK_ANY and ANY_SSC enums which are used if the setting is independent of clock rate or SSC type. Signed-off-by: Roger Quadros Signed-off-by: Swapnil Jakhade Link: https://lore.kernel.org/r/20230530143853.26571-3-sjakhade@cadence.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-torrent.c | 1661 ++++++--------------- 1 file changed, 485 insertions(+), 1176 deletions(-) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index 4b027e23aeb36..4795b440fb776 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -32,10 +32,6 @@ #define MAX_NUM_LANES 4 #define DEFAULT_MAX_BIT_RATE 8100 /* in Mbps */ -#define NUM_SSC_MODE 3 -#define NUM_REF_CLK 4 -#define NUM_PHY_TYPE 7 - #define POLL_TIMEOUT_US 5000 #define PLL_LOCK_TIMEOUT 100000 @@ -307,15 +303,42 @@ enum cdns_torrent_ref_clk { CLK_19_2_MHZ, CLK_25_MHZ, CLK_100_MHZ, - CLK_156_25_MHZ + CLK_156_25_MHZ, + CLK_ANY, }; enum cdns_torrent_ssc_mode { NO_SSC, EXTERNAL_SSC, - INTERNAL_SSC + INTERNAL_SSC, + ANY_SSC, }; +/* Unique key id for vals table entry + * REFCLK0_RATE | REFCLK1_RATE | LINK0_TYPE | LINK1_TYPE | SSC_TYPE + */ +#define REFCLK0_SHIFT 12 +#define REFCLK0_MASK GENMASK(14, 12) +#define REFCLK1_SHIFT 9 +#define REFCLK1_MASK GENMASK(11, 9) +#define LINK0_SHIFT 6 +#define LINK0_MASK GENMASK(8, 6) +#define LINK1_SHIFT 3 +#define LINK1_MASK GENMASK(5, 3) +#define SSC_SHIFT 0 +#define SSC_MASK GENMASK(2, 0) + +#define CDNS_TORRENT_KEY(refclk0, refclk1, link0, link1, ssc) \ + ((((refclk0) << REFCLK0_SHIFT) & REFCLK0_MASK) | \ + (((refclk1) << REFCLK1_SHIFT) & REFCLK1_MASK) | \ + (((link0) << LINK0_SHIFT) & LINK0_MASK) | \ + (((link1) << LINK1_SHIFT) & LINK1_MASK) | \ + (((ssc) << SSC_SHIFT) & SSC_MASK)) + +#define CDNS_TORRENT_KEY_ANYCLK(link0, link1) \ + CDNS_TORRENT_KEY(CLK_ANY, CLK_ANY, \ + (link0), (link1), ANY_SSC) + struct cdns_torrent_inst { struct phy *phy; u32 mlane; @@ -402,23 +425,26 @@ struct cdns_torrent_vals { u32 num_regs; }; +struct cdns_torrent_vals_entry { + u32 key; + struct cdns_torrent_vals *vals; +}; + +struct cdns_torrent_vals_table { + struct cdns_torrent_vals_entry *entries; + u32 num_entries; +}; + struct cdns_torrent_data { u8 block_offset_shift; u8 reg_offset_shift; - struct cdns_torrent_vals *link_cmn_vals[NUM_PHY_TYPE][NUM_PHY_TYPE] - [NUM_SSC_MODE]; - struct cdns_torrent_vals *xcvr_diag_vals[NUM_PHY_TYPE][NUM_PHY_TYPE] - [NUM_SSC_MODE]; - struct cdns_torrent_vals *pcs_cmn_vals[NUM_PHY_TYPE][NUM_PHY_TYPE] - [NUM_SSC_MODE]; - struct cdns_torrent_vals *phy_pma_cmn_vals[NUM_PHY_TYPE][NUM_PHY_TYPE] - [NUM_SSC_MODE]; - struct cdns_torrent_vals *cmn_vals[NUM_REF_CLK][NUM_PHY_TYPE] - [NUM_PHY_TYPE][NUM_SSC_MODE]; - struct cdns_torrent_vals *tx_ln_vals[NUM_REF_CLK][NUM_PHY_TYPE] - [NUM_PHY_TYPE][NUM_SSC_MODE]; - struct cdns_torrent_vals *rx_ln_vals[NUM_REF_CLK][NUM_PHY_TYPE] - [NUM_PHY_TYPE][NUM_SSC_MODE]; + struct cdns_torrent_vals_table link_cmn_vals_tbl; + struct cdns_torrent_vals_table xcvr_diag_vals_tbl; + struct cdns_torrent_vals_table pcs_cmn_vals_tbl; + struct cdns_torrent_vals_table phy_pma_cmn_vals_tbl; + struct cdns_torrent_vals_table cmn_vals_tbl; + struct cdns_torrent_vals_table tx_ln_vals_tbl; + struct cdns_torrent_vals_table rx_ln_vals_tbl; }; struct cdns_regmap_cdb_context { @@ -427,6 +453,24 @@ struct cdns_regmap_cdb_context { u8 reg_offset_shift; }; +static struct cdns_torrent_vals *cdns_torrent_get_tbl_vals(const struct cdns_torrent_vals_table *tbl, + enum cdns_torrent_ref_clk refclk0, + enum cdns_torrent_ref_clk refclk1, + enum cdns_torrent_phy_type link0, + enum cdns_torrent_phy_type link1, + enum cdns_torrent_ssc_mode ssc) +{ + int i; + u32 key = CDNS_TORRENT_KEY(refclk0, refclk1, link0, link1, ssc); + + for (i = 0; i < tbl->num_entries; i++) { + if (tbl->entries[i].key == key) + return tbl->entries[i].vals; + } + + return NULL; +} + static int cdns_regmap_write(void *context, unsigned int reg, unsigned int val) { struct cdns_regmap_cdb_context *ctx = context; @@ -2277,7 +2321,10 @@ static int cdns_torrent_phy_init(struct phy *phy) ssc = NO_SSC; /* PHY configuration specific registers for single link */ - link_cmn_vals = init_data->link_cmn_vals[phy_type][TYPE_NONE][ssc]; + link_cmn_vals = cdns_torrent_get_tbl_vals(&init_data->link_cmn_vals_tbl, + CLK_ANY, CLK_ANY, + phy_type, TYPE_NONE, + ANY_SSC); if (link_cmn_vals) { reg_pairs = link_cmn_vals->reg_pairs; num_regs = link_cmn_vals->num_regs; @@ -2294,7 +2341,10 @@ static int cdns_torrent_phy_init(struct phy *phy) reg_pairs[i].val); } - xcvr_diag_vals = init_data->xcvr_diag_vals[phy_type][TYPE_NONE][ssc]; + xcvr_diag_vals = cdns_torrent_get_tbl_vals(&init_data->xcvr_diag_vals_tbl, + CLK_ANY, CLK_ANY, + phy_type, TYPE_NONE, + ANY_SSC); if (xcvr_diag_vals) { reg_pairs = xcvr_diag_vals->reg_pairs; num_regs = xcvr_diag_vals->num_regs; @@ -2307,7 +2357,10 @@ static int cdns_torrent_phy_init(struct phy *phy) } /* PHY PCS common registers configurations */ - pcs_cmn_vals = init_data->pcs_cmn_vals[phy_type][TYPE_NONE][ssc]; + pcs_cmn_vals = cdns_torrent_get_tbl_vals(&init_data->pcs_cmn_vals_tbl, + CLK_ANY, CLK_ANY, + phy_type, TYPE_NONE, + ANY_SSC); if (pcs_cmn_vals) { reg_pairs = pcs_cmn_vals->reg_pairs; num_regs = pcs_cmn_vals->num_regs; @@ -2318,7 +2371,10 @@ static int cdns_torrent_phy_init(struct phy *phy) } /* PHY PMA common registers configurations */ - phy_pma_cmn_vals = init_data->phy_pma_cmn_vals[phy_type][TYPE_NONE][ssc]; + phy_pma_cmn_vals = cdns_torrent_get_tbl_vals(&init_data->phy_pma_cmn_vals_tbl, + CLK_ANY, CLK_ANY, + phy_type, TYPE_NONE, + ANY_SSC); if (phy_pma_cmn_vals) { reg_pairs = phy_pma_cmn_vals->reg_pairs; num_regs = phy_pma_cmn_vals->num_regs; @@ -2329,7 +2385,10 @@ static int cdns_torrent_phy_init(struct phy *phy) } /* PMA common registers configurations */ - cmn_vals = init_data->cmn_vals[ref_clk][phy_type][TYPE_NONE][ssc]; + cmn_vals = cdns_torrent_get_tbl_vals(&init_data->cmn_vals_tbl, + ref_clk, ref_clk, + phy_type, TYPE_NONE, + ssc); if (cmn_vals) { reg_pairs = cmn_vals->reg_pairs; num_regs = cmn_vals->num_regs; @@ -2340,7 +2399,10 @@ static int cdns_torrent_phy_init(struct phy *phy) } /* PMA TX lane registers configurations */ - tx_ln_vals = init_data->tx_ln_vals[ref_clk][phy_type][TYPE_NONE][ssc]; + tx_ln_vals = cdns_torrent_get_tbl_vals(&init_data->tx_ln_vals_tbl, + ref_clk, ref_clk, + phy_type, TYPE_NONE, + ssc); if (tx_ln_vals) { reg_pairs = tx_ln_vals->reg_pairs; num_regs = tx_ln_vals->num_regs; @@ -2353,7 +2415,10 @@ static int cdns_torrent_phy_init(struct phy *phy) } /* PMA RX lane registers configurations */ - rx_ln_vals = init_data->rx_ln_vals[ref_clk][phy_type][TYPE_NONE][ssc]; + rx_ln_vals = cdns_torrent_get_tbl_vals(&init_data->rx_ln_vals_tbl, + ref_clk, ref_clk, + phy_type, TYPE_NONE, + ssc); if (rx_ln_vals) { reg_pairs = rx_ln_vals->reg_pairs; num_regs = rx_ln_vals->num_regs; @@ -2442,7 +2507,9 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) * being configured, but these can be different for particular * PHY type and are per lane. */ - link_cmn_vals = init_data->link_cmn_vals[phy_t1][phy_t2][ssc]; + link_cmn_vals = cdns_torrent_get_tbl_vals(&init_data->link_cmn_vals_tbl, + CLK_ANY, CLK_ANY, + phy_t1, phy_t2, ANY_SSC); if (link_cmn_vals) { reg_pairs = link_cmn_vals->reg_pairs; num_regs = link_cmn_vals->num_regs; @@ -2460,7 +2527,9 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) reg_pairs[i].val); } - xcvr_diag_vals = init_data->xcvr_diag_vals[phy_t1][phy_t2][ssc]; + xcvr_diag_vals = cdns_torrent_get_tbl_vals(&init_data->xcvr_diag_vals_tbl, + CLK_ANY, CLK_ANY, + phy_t1, phy_t2, ANY_SSC); if (xcvr_diag_vals) { reg_pairs = xcvr_diag_vals->reg_pairs; num_regs = xcvr_diag_vals->num_regs; @@ -2473,7 +2542,9 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) } /* PHY PCS common registers configurations */ - pcs_cmn_vals = init_data->pcs_cmn_vals[phy_t1][phy_t2][ssc]; + pcs_cmn_vals = cdns_torrent_get_tbl_vals(&init_data->pcs_cmn_vals_tbl, + CLK_ANY, CLK_ANY, + phy_t1, phy_t2, ANY_SSC); if (pcs_cmn_vals) { reg_pairs = pcs_cmn_vals->reg_pairs; num_regs = pcs_cmn_vals->num_regs; @@ -2484,7 +2555,9 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) } /* PMA common registers configurations */ - cmn_vals = init_data->cmn_vals[ref_clk][phy_t1][phy_t2][ssc]; + cmn_vals = cdns_torrent_get_tbl_vals(&init_data->cmn_vals_tbl, + ref_clk, ref_clk, + phy_t1, phy_t2, ssc); if (cmn_vals) { reg_pairs = cmn_vals->reg_pairs; num_regs = cmn_vals->num_regs; @@ -2495,7 +2568,9 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) } /* PMA TX lane registers configurations */ - tx_ln_vals = init_data->tx_ln_vals[ref_clk][phy_t1][phy_t2][ssc]; + tx_ln_vals = cdns_torrent_get_tbl_vals(&init_data->tx_ln_vals_tbl, + ref_clk, ref_clk, + phy_t1, phy_t2, ssc); if (tx_ln_vals) { reg_pairs = tx_ln_vals->reg_pairs; num_regs = tx_ln_vals->num_regs; @@ -2508,7 +2583,9 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) } /* PMA RX lane registers configurations */ - rx_ln_vals = init_data->rx_ln_vals[ref_clk][phy_t1][phy_t2][ssc]; + rx_ln_vals = cdns_torrent_get_tbl_vals(&init_data->rx_ln_vals_tbl, + ref_clk, ref_clk, + phy_t1, phy_t2, ssc); if (rx_ln_vals) { reg_pairs = rx_ln_vals->reg_pairs; num_regs = rx_ln_vals->num_regs; @@ -4081,1169 +4158,401 @@ static struct cdns_torrent_vals pcie_100_no_ssc_rx_ln_vals = { .num_regs = ARRAY_SIZE(pcie_100_ext_no_ssc_rx_ln_regs), }; +static struct cdns_torrent_vals_entry link_cmn_vals_entries[] = { + {CDNS_TORRENT_KEY_ANYCLK(TYPE_DP, TYPE_NONE), &sl_dp_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_DP, TYPE_PCIE), &pcie_dp_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_DP, TYPE_USB), &usb_dp_link_cmn_vals}, + + {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_NONE), NULL}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_SGMII), &pcie_sgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_QSGMII), &pcie_sgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_USB), &pcie_usb_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_DP), &pcie_dp_link_cmn_vals}, + + {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_NONE), &sl_sgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_PCIE), &pcie_sgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_USB), &usb_sgmii_link_cmn_vals}, + + {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_NONE), &sl_sgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_PCIE), &pcie_sgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_USB), &usb_sgmii_link_cmn_vals}, + + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_NONE), &sl_usb_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_PCIE), &pcie_usb_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_SGMII), &usb_sgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_QSGMII), &usb_sgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_DP), &usb_dp_link_cmn_vals}, + + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_NONE), &sl_usxgmii_link_cmn_vals}, +}; + +static struct cdns_torrent_vals_entry xcvr_diag_vals_entries[] = { + {CDNS_TORRENT_KEY_ANYCLK(TYPE_DP, TYPE_NONE), &sl_dp_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_DP, TYPE_PCIE), &dp_pcie_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_DP, TYPE_USB), &dp_usb_xcvr_diag_ln_vals}, + + {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_NONE), NULL}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_SGMII), &pcie_sgmii_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_QSGMII), &pcie_sgmii_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_USB), &pcie_usb_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_DP), &pcie_dp_xcvr_diag_ln_vals}, + + {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_NONE), &sl_sgmii_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_PCIE), &sgmii_pcie_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_USB), &sgmii_usb_xcvr_diag_ln_vals}, + + {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_NONE), &sl_sgmii_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_PCIE), &sgmii_pcie_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_USB), &sgmii_usb_xcvr_diag_ln_vals}, + + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_NONE), &sl_usb_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_PCIE), &usb_pcie_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_SGMII), &usb_sgmii_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_QSGMII), &usb_sgmii_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_DP), &usb_dp_xcvr_diag_ln_vals}, + + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_NONE), &sl_usxgmii_xcvr_diag_ln_vals}, +}; + +static struct cdns_torrent_vals_entry pcs_cmn_vals_entries[] = { + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_NONE), &usb_phy_pcs_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_PCIE), &usb_phy_pcs_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_SGMII), &usb_phy_pcs_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_QSGMII), &usb_phy_pcs_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_DP), &usb_phy_pcs_cmn_vals}, +}; + +static struct cdns_torrent_vals_entry cmn_vals_entries[] = { + {CDNS_TORRENT_KEY(CLK_19_2_MHZ, CLK_19_2_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_19_2_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_25_MHZ, CLK_25_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_25_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_PCIE, NO_SSC), &dp_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_USB, NO_SSC), &sl_dp_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, INTERNAL_SSC), &sl_pcie_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, NO_SSC), &pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, EXTERNAL_SSC), &pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, INTERNAL_SSC), &pcie_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, NO_SSC), &pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, EXTERNAL_SSC), &pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, INTERNAL_SSC), &pcie_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, NO_SSC), &pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, EXTERNAL_SSC), &pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, INTERNAL_SSC), &pcie_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_NONE, NO_SSC), &sl_sgmii_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, NO_SSC), &sgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &sgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &sgmii_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &sgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &sgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &sgmii_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_NONE, NO_SSC), &sl_qsgmii_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, NO_SSC), &qsgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &qsgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &qsgmii_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &qsgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &qsgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &qsgmii_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, NO_SSC), &sl_usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, EXTERNAL_SSC), &sl_usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, INTERNAL_SSC), &sl_usb_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, NO_SSC), &usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, EXTERNAL_SSC), &usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, INTERNAL_SSC), &usb_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, NO_SSC), &sl_usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, EXTERNAL_SSC), &sl_usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, INTERNAL_SSC), &sl_usb_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, NO_SSC), &sl_usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, EXTERNAL_SSC), &sl_usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, INTERNAL_SSC), &sl_usb_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &sl_usxgmii_156_25_no_ssc_cmn_vals}, +}; + +static struct cdns_torrent_vals_entry cdns_tx_ln_vals_entries[] = { + {CDNS_TORRENT_KEY(CLK_19_2_MHZ, CLK_19_2_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_19_2_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_25_MHZ, CLK_25_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_25_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_PCIE, NO_SSC), &dp_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_USB, NO_SSC), &dp_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, INTERNAL_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, INTERNAL_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, INTERNAL_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, INTERNAL_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_NONE, NO_SSC), &sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, NO_SSC), &sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_NONE, NO_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, NO_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_tx_ln_vals}, +}; + +static struct cdns_torrent_vals_entry cdns_rx_ln_vals_entries[] = { + {CDNS_TORRENT_KEY(CLK_19_2_MHZ, CLK_19_2_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_19_2_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_25_MHZ, CLK_25_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_25_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_PCIE, NO_SSC), &dp_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_USB, NO_SSC), &dp_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, EXTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, INTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, EXTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, INTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, EXTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, INTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, EXTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, INTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_NONE, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_NONE, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, NO_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, EXTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, INTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, NO_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, EXTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, INTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, NO_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, EXTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, INTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, NO_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, EXTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, INTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_rx_ln_vals}, +}; + static const struct cdns_torrent_data cdns_map_torrent = { .block_offset_shift = 0x2, .reg_offset_shift = 0x2, - .link_cmn_vals = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_link_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &pcie_dp_link_cmn_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &usb_dp_link_cmn_vals, - }, - }, - [TYPE_PCIE] = { - [TYPE_NONE] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = NULL, - }, - [TYPE_SGMII] = { - [NO_SSC] = &pcie_sgmii_link_cmn_vals, - [EXTERNAL_SSC] = &pcie_sgmii_link_cmn_vals, - [INTERNAL_SSC] = &pcie_sgmii_link_cmn_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &pcie_sgmii_link_cmn_vals, - [EXTERNAL_SSC] = &pcie_sgmii_link_cmn_vals, - [INTERNAL_SSC] = &pcie_sgmii_link_cmn_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &pcie_usb_link_cmn_vals, - [EXTERNAL_SSC] = &pcie_usb_link_cmn_vals, - [INTERNAL_SSC] = &pcie_usb_link_cmn_vals, - }, - [TYPE_DP] = { - [NO_SSC] = &pcie_dp_link_cmn_vals, - }, - }, - [TYPE_SGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_sgmii_link_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &pcie_sgmii_link_cmn_vals, - [EXTERNAL_SSC] = &pcie_sgmii_link_cmn_vals, - [INTERNAL_SSC] = &pcie_sgmii_link_cmn_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &usb_sgmii_link_cmn_vals, - [EXTERNAL_SSC] = &usb_sgmii_link_cmn_vals, - [INTERNAL_SSC] = &usb_sgmii_link_cmn_vals, - }, - }, - [TYPE_QSGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_sgmii_link_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &pcie_sgmii_link_cmn_vals, - [EXTERNAL_SSC] = &pcie_sgmii_link_cmn_vals, - [INTERNAL_SSC] = &pcie_sgmii_link_cmn_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &usb_sgmii_link_cmn_vals, - [EXTERNAL_SSC] = &usb_sgmii_link_cmn_vals, - [INTERNAL_SSC] = &usb_sgmii_link_cmn_vals, - }, - }, - [TYPE_USB] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_usb_link_cmn_vals, - [EXTERNAL_SSC] = &sl_usb_link_cmn_vals, - [INTERNAL_SSC] = &sl_usb_link_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &pcie_usb_link_cmn_vals, - [EXTERNAL_SSC] = &pcie_usb_link_cmn_vals, - [INTERNAL_SSC] = &pcie_usb_link_cmn_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &usb_sgmii_link_cmn_vals, - [EXTERNAL_SSC] = &usb_sgmii_link_cmn_vals, - [INTERNAL_SSC] = &usb_sgmii_link_cmn_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &usb_sgmii_link_cmn_vals, - [EXTERNAL_SSC] = &usb_sgmii_link_cmn_vals, - [INTERNAL_SSC] = &usb_sgmii_link_cmn_vals, - }, - [TYPE_DP] = { - [NO_SSC] = &usb_dp_link_cmn_vals, - }, - }, - [TYPE_USXGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_usxgmii_link_cmn_vals, - }, - }, - }, - .xcvr_diag_vals = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_xcvr_diag_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &dp_pcie_xcvr_diag_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &dp_usb_xcvr_diag_ln_vals, - }, - }, - [TYPE_PCIE] = { - [TYPE_NONE] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = NULL, - }, - [TYPE_SGMII] = { - [NO_SSC] = &pcie_sgmii_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &pcie_sgmii_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &pcie_sgmii_xcvr_diag_ln_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &pcie_sgmii_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &pcie_sgmii_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &pcie_sgmii_xcvr_diag_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &pcie_usb_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &pcie_usb_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &pcie_usb_xcvr_diag_ln_vals, - }, - [TYPE_DP] = { - [NO_SSC] = &pcie_dp_xcvr_diag_ln_vals, - }, - }, - [TYPE_SGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_sgmii_xcvr_diag_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &sgmii_pcie_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &sgmii_pcie_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &sgmii_pcie_xcvr_diag_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &sgmii_usb_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &sgmii_usb_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &sgmii_usb_xcvr_diag_ln_vals, - }, - }, - [TYPE_QSGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_sgmii_xcvr_diag_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &sgmii_pcie_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &sgmii_pcie_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &sgmii_pcie_xcvr_diag_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &sgmii_usb_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &sgmii_usb_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &sgmii_usb_xcvr_diag_ln_vals, - }, - }, - [TYPE_USB] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_usb_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &sl_usb_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &sl_usb_xcvr_diag_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &usb_pcie_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &usb_pcie_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &usb_pcie_xcvr_diag_ln_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &usb_sgmii_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &usb_sgmii_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &usb_sgmii_xcvr_diag_ln_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &usb_sgmii_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &usb_sgmii_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &usb_sgmii_xcvr_diag_ln_vals, - }, - [TYPE_DP] = { - [NO_SSC] = &usb_dp_xcvr_diag_ln_vals, - }, - }, - [TYPE_USXGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_usxgmii_xcvr_diag_ln_vals, - }, - }, + .link_cmn_vals_tbl = { + .entries = link_cmn_vals_entries, + .num_entries = ARRAY_SIZE(link_cmn_vals_entries), }, - .pcs_cmn_vals = { - [TYPE_USB] = { - [TYPE_NONE] = { - [NO_SSC] = &usb_phy_pcs_cmn_vals, - [EXTERNAL_SSC] = &usb_phy_pcs_cmn_vals, - [INTERNAL_SSC] = &usb_phy_pcs_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &usb_phy_pcs_cmn_vals, - [EXTERNAL_SSC] = &usb_phy_pcs_cmn_vals, - [INTERNAL_SSC] = &usb_phy_pcs_cmn_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &usb_phy_pcs_cmn_vals, - [EXTERNAL_SSC] = &usb_phy_pcs_cmn_vals, - [INTERNAL_SSC] = &usb_phy_pcs_cmn_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &usb_phy_pcs_cmn_vals, - [EXTERNAL_SSC] = &usb_phy_pcs_cmn_vals, - [INTERNAL_SSC] = &usb_phy_pcs_cmn_vals, - }, - [TYPE_DP] = { - [NO_SSC] = &usb_phy_pcs_cmn_vals, - }, - }, + .xcvr_diag_vals_tbl = { + .entries = xcvr_diag_vals_entries, + .num_entries = ARRAY_SIZE(xcvr_diag_vals_entries), }, - .phy_pma_cmn_vals = { - [TYPE_USXGMII] = { - [TYPE_NONE] = { - [NO_SSC] = NULL, - }, - }, + .pcs_cmn_vals_tbl = { + .entries = pcs_cmn_vals_entries, + .num_entries = ARRAY_SIZE(pcs_cmn_vals_entries), }, - .cmn_vals = { - [CLK_19_2_MHZ] = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_19_2_no_ssc_cmn_vals, - }, - }, - }, - [CLK_25_MHZ] = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_25_no_ssc_cmn_vals, - }, - }, - }, - [CLK_100_MHZ] = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_100_no_ssc_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &dp_100_no_ssc_cmn_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &sl_dp_100_no_ssc_cmn_vals, - }, - }, - [TYPE_PCIE] = { - [TYPE_NONE] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = &sl_pcie_100_int_ssc_cmn_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &pcie_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &pcie_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &pcie_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, - }, - [TYPE_DP] = { - [NO_SSC] = NULL, - }, - }, - [TYPE_SGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_sgmii_100_no_ssc_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &sgmii_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &sgmii_100_int_ssc_cmn_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &sgmii_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &sgmii_100_no_ssc_cmn_vals, - }, - }, - [TYPE_QSGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_qsgmii_100_no_ssc_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &qsgmii_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &qsgmii_100_int_ssc_cmn_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &qsgmii_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &qsgmii_100_no_ssc_cmn_vals, - }, - }, - [TYPE_USB] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &usb_100_int_ssc_cmn_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, - }, - [TYPE_DP] = { - [NO_SSC] = &usb_100_no_ssc_cmn_vals, - }, - }, - }, - [CLK_156_25_MHZ] = { - [TYPE_USXGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_usxgmii_156_25_no_ssc_cmn_vals, - }, - }, - }, + .cmn_vals_tbl = { + .entries = cmn_vals_entries, + .num_entries = ARRAY_SIZE(cmn_vals_entries), }, - .tx_ln_vals = { - [CLK_19_2_MHZ] = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_19_2_no_ssc_tx_ln_vals, - }, - }, - }, - [CLK_25_MHZ] = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_25_no_ssc_tx_ln_vals, - }, - }, - }, - [CLK_100_MHZ] = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_100_no_ssc_tx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &dp_100_no_ssc_tx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &dp_100_no_ssc_tx_ln_vals, - }, - }, - [TYPE_PCIE] = { - [TYPE_NONE] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = NULL, - }, - [TYPE_SGMII] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = NULL, - }, - [TYPE_QSGMII] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = NULL, - }, - [TYPE_USB] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = NULL, - }, - [TYPE_DP] = { - [NO_SSC] = NULL, - }, - }, - [TYPE_SGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - }, - }, - [TYPE_QSGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - }, - }, - [TYPE_USB] = { - [TYPE_NONE] = { - [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - }, - [TYPE_DP] = { - [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, - }, - }, - }, - [CLK_156_25_MHZ] = { - [TYPE_USXGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &usxgmii_156_25_no_ssc_tx_ln_vals, - }, - }, - }, + .tx_ln_vals_tbl = { + .entries = cdns_tx_ln_vals_entries, + .num_entries = ARRAY_SIZE(cdns_tx_ln_vals_entries), }, - .rx_ln_vals = { - [CLK_19_2_MHZ] = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_19_2_no_ssc_rx_ln_vals, - }, - }, - }, - [CLK_25_MHZ] = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_25_no_ssc_rx_ln_vals, - }, - }, - }, - [CLK_100_MHZ] = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_100_no_ssc_rx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &dp_100_no_ssc_rx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &dp_100_no_ssc_rx_ln_vals, - }, - }, - [TYPE_PCIE] = { - [TYPE_NONE] = { - [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - }, - [TYPE_DP] = { - [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, - }, - }, - [TYPE_SGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - }, - }, - [TYPE_QSGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - }, - }, - [TYPE_USB] = { - [TYPE_NONE] = { - [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - }, - [TYPE_DP] = { - [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, - }, - }, - }, - [CLK_156_25_MHZ] = { - [TYPE_USXGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &usxgmii_156_25_no_ssc_rx_ln_vals, - }, - }, - }, + .rx_ln_vals_tbl = { + .entries = cdns_rx_ln_vals_entries, + .num_entries = ARRAY_SIZE(cdns_rx_ln_vals_entries), }, }; +static struct cdns_torrent_vals_entry j721e_phy_pma_cmn_vals_entries[] = { + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_NONE), &ti_usxgmii_phy_pma_cmn_vals}, +}; + +static struct cdns_torrent_vals_entry ti_tx_ln_vals_entries[] = { + {CDNS_TORRENT_KEY(CLK_19_2_MHZ, CLK_19_2_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_19_2_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_25_MHZ, CLK_25_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_25_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_PCIE, NO_SSC), &dp_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_USB, NO_SSC), &dp_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, INTERNAL_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, INTERNAL_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, INTERNAL_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, INTERNAL_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_NONE, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_NONE, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_tx_ln_vals}, +}; + static const struct cdns_torrent_data ti_j721e_map_torrent = { .block_offset_shift = 0x0, .reg_offset_shift = 0x1, - .link_cmn_vals = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_link_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &pcie_dp_link_cmn_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &usb_dp_link_cmn_vals, - }, - }, - [TYPE_PCIE] = { - [TYPE_NONE] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = NULL, - }, - [TYPE_SGMII] = { - [NO_SSC] = &pcie_sgmii_link_cmn_vals, - [EXTERNAL_SSC] = &pcie_sgmii_link_cmn_vals, - [INTERNAL_SSC] = &pcie_sgmii_link_cmn_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &pcie_sgmii_link_cmn_vals, - [EXTERNAL_SSC] = &pcie_sgmii_link_cmn_vals, - [INTERNAL_SSC] = &pcie_sgmii_link_cmn_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &pcie_usb_link_cmn_vals, - [EXTERNAL_SSC] = &pcie_usb_link_cmn_vals, - [INTERNAL_SSC] = &pcie_usb_link_cmn_vals, - }, - [TYPE_DP] = { - [NO_SSC] = &pcie_dp_link_cmn_vals, - }, - }, - [TYPE_SGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_sgmii_link_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &pcie_sgmii_link_cmn_vals, - [EXTERNAL_SSC] = &pcie_sgmii_link_cmn_vals, - [INTERNAL_SSC] = &pcie_sgmii_link_cmn_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &usb_sgmii_link_cmn_vals, - [EXTERNAL_SSC] = &usb_sgmii_link_cmn_vals, - [INTERNAL_SSC] = &usb_sgmii_link_cmn_vals, - }, - }, - [TYPE_QSGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_sgmii_link_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &pcie_sgmii_link_cmn_vals, - [EXTERNAL_SSC] = &pcie_sgmii_link_cmn_vals, - [INTERNAL_SSC] = &pcie_sgmii_link_cmn_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &usb_sgmii_link_cmn_vals, - [EXTERNAL_SSC] = &usb_sgmii_link_cmn_vals, - [INTERNAL_SSC] = &usb_sgmii_link_cmn_vals, - }, - }, - [TYPE_USB] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_usb_link_cmn_vals, - [EXTERNAL_SSC] = &sl_usb_link_cmn_vals, - [INTERNAL_SSC] = &sl_usb_link_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &pcie_usb_link_cmn_vals, - [EXTERNAL_SSC] = &pcie_usb_link_cmn_vals, - [INTERNAL_SSC] = &pcie_usb_link_cmn_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &usb_sgmii_link_cmn_vals, - [EXTERNAL_SSC] = &usb_sgmii_link_cmn_vals, - [INTERNAL_SSC] = &usb_sgmii_link_cmn_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &usb_sgmii_link_cmn_vals, - [EXTERNAL_SSC] = &usb_sgmii_link_cmn_vals, - [INTERNAL_SSC] = &usb_sgmii_link_cmn_vals, - }, - [TYPE_DP] = { - [NO_SSC] = &usb_dp_link_cmn_vals, - }, - }, - [TYPE_USXGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_usxgmii_link_cmn_vals, - }, - }, + .link_cmn_vals_tbl = { + .entries = link_cmn_vals_entries, + .num_entries = ARRAY_SIZE(link_cmn_vals_entries), }, - .xcvr_diag_vals = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_xcvr_diag_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &dp_pcie_xcvr_diag_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &dp_usb_xcvr_diag_ln_vals, - }, - }, - [TYPE_PCIE] = { - [TYPE_NONE] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = NULL, - }, - [TYPE_SGMII] = { - [NO_SSC] = &pcie_sgmii_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &pcie_sgmii_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &pcie_sgmii_xcvr_diag_ln_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &pcie_sgmii_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &pcie_sgmii_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &pcie_sgmii_xcvr_diag_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &pcie_usb_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &pcie_usb_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &pcie_usb_xcvr_diag_ln_vals, - }, - [TYPE_DP] = { - [NO_SSC] = &pcie_dp_xcvr_diag_ln_vals, - }, - }, - [TYPE_SGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_sgmii_xcvr_diag_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &sgmii_pcie_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &sgmii_pcie_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &sgmii_pcie_xcvr_diag_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &sgmii_usb_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &sgmii_usb_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &sgmii_usb_xcvr_diag_ln_vals, - }, - }, - [TYPE_QSGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_sgmii_xcvr_diag_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &sgmii_pcie_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &sgmii_pcie_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &sgmii_pcie_xcvr_diag_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &sgmii_usb_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &sgmii_usb_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &sgmii_usb_xcvr_diag_ln_vals, - }, - }, - [TYPE_USB] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_usb_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &sl_usb_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &sl_usb_xcvr_diag_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &usb_pcie_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &usb_pcie_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &usb_pcie_xcvr_diag_ln_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &usb_sgmii_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &usb_sgmii_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &usb_sgmii_xcvr_diag_ln_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &usb_sgmii_xcvr_diag_ln_vals, - [EXTERNAL_SSC] = &usb_sgmii_xcvr_diag_ln_vals, - [INTERNAL_SSC] = &usb_sgmii_xcvr_diag_ln_vals, - }, - [TYPE_DP] = { - [NO_SSC] = &usb_dp_xcvr_diag_ln_vals, - }, - }, - [TYPE_USXGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_usxgmii_xcvr_diag_ln_vals, - }, - }, + .xcvr_diag_vals_tbl = { + .entries = xcvr_diag_vals_entries, + .num_entries = ARRAY_SIZE(xcvr_diag_vals_entries), }, - .pcs_cmn_vals = { - [TYPE_USB] = { - [TYPE_NONE] = { - [NO_SSC] = &usb_phy_pcs_cmn_vals, - [EXTERNAL_SSC] = &usb_phy_pcs_cmn_vals, - [INTERNAL_SSC] = &usb_phy_pcs_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &usb_phy_pcs_cmn_vals, - [EXTERNAL_SSC] = &usb_phy_pcs_cmn_vals, - [INTERNAL_SSC] = &usb_phy_pcs_cmn_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &usb_phy_pcs_cmn_vals, - [EXTERNAL_SSC] = &usb_phy_pcs_cmn_vals, - [INTERNAL_SSC] = &usb_phy_pcs_cmn_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &usb_phy_pcs_cmn_vals, - [EXTERNAL_SSC] = &usb_phy_pcs_cmn_vals, - [INTERNAL_SSC] = &usb_phy_pcs_cmn_vals, - }, - [TYPE_DP] = { - [NO_SSC] = &usb_phy_pcs_cmn_vals, - }, - }, + .pcs_cmn_vals_tbl = { + .entries = pcs_cmn_vals_entries, + .num_entries = ARRAY_SIZE(pcs_cmn_vals_entries), }, - .phy_pma_cmn_vals = { - [TYPE_USXGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &ti_usxgmii_phy_pma_cmn_vals, - }, - }, + .phy_pma_cmn_vals_tbl = { + .entries = j721e_phy_pma_cmn_vals_entries, + .num_entries = ARRAY_SIZE(j721e_phy_pma_cmn_vals_entries), }, - .cmn_vals = { - [CLK_19_2_MHZ] = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_19_2_no_ssc_cmn_vals, - }, - }, - }, - [CLK_25_MHZ] = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_25_no_ssc_cmn_vals, - }, - }, - }, - [CLK_100_MHZ] = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_100_no_ssc_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &dp_100_no_ssc_cmn_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &sl_dp_100_no_ssc_cmn_vals, - }, - }, - [TYPE_PCIE] = { - [TYPE_NONE] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = &sl_pcie_100_int_ssc_cmn_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &pcie_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &pcie_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &pcie_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, - }, - [TYPE_DP] = { - [NO_SSC] = NULL, - }, - }, - [TYPE_SGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_sgmii_100_no_ssc_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &sgmii_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &sgmii_100_int_ssc_cmn_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &sgmii_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &sgmii_100_no_ssc_cmn_vals, - }, - }, - [TYPE_QSGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_qsgmii_100_no_ssc_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &qsgmii_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &qsgmii_100_int_ssc_cmn_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &qsgmii_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &qsgmii_100_no_ssc_cmn_vals, - }, - }, - [TYPE_USB] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &usb_100_int_ssc_cmn_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, - }, - [TYPE_DP] = { - [NO_SSC] = &usb_100_no_ssc_cmn_vals, - }, - }, - }, - [CLK_156_25_MHZ] = { - [TYPE_USXGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_usxgmii_156_25_no_ssc_cmn_vals, - }, - }, - }, + .cmn_vals_tbl = { + .entries = cmn_vals_entries, + .num_entries = ARRAY_SIZE(cmn_vals_entries), }, - .tx_ln_vals = { - [CLK_19_2_MHZ] = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_19_2_no_ssc_tx_ln_vals, - }, - }, - }, - [CLK_25_MHZ] = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_25_no_ssc_tx_ln_vals, - }, - }, - }, - [CLK_100_MHZ] = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_100_no_ssc_tx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &dp_100_no_ssc_tx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &dp_100_no_ssc_tx_ln_vals, - }, - }, - [TYPE_PCIE] = { - [TYPE_NONE] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = NULL, - }, - [TYPE_SGMII] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = NULL, - }, - [TYPE_QSGMII] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = NULL, - }, - [TYPE_USB] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = NULL, - }, - [TYPE_DP] = { - [NO_SSC] = NULL, - }, - }, - [TYPE_SGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, - }, - }, - [TYPE_QSGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, - }, - }, - [TYPE_USB] = { - [TYPE_NONE] = { - [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - }, - [TYPE_DP] = { - [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, - }, - }, - }, - [CLK_156_25_MHZ] = { - [TYPE_USXGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &usxgmii_156_25_no_ssc_tx_ln_vals, - }, - }, - }, + .tx_ln_vals_tbl = { + .entries = ti_tx_ln_vals_entries, + .num_entries = ARRAY_SIZE(ti_tx_ln_vals_entries), }, - .rx_ln_vals = { - [CLK_19_2_MHZ] = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_19_2_no_ssc_rx_ln_vals, - }, - }, - }, - [CLK_25_MHZ] = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_25_no_ssc_rx_ln_vals, - }, - }, - }, - [CLK_100_MHZ] = { - [TYPE_DP] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_dp_100_no_ssc_rx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &dp_100_no_ssc_rx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &dp_100_no_ssc_rx_ln_vals, - }, - }, - [TYPE_PCIE] = { - [TYPE_NONE] = { - [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - }, - [TYPE_DP] = { - [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, - }, - }, - [TYPE_SGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - }, - }, - [TYPE_QSGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - }, - }, - [TYPE_USB] = { - [TYPE_NONE] = { - [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - }, - [TYPE_DP] = { - [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, - }, - }, - }, - [CLK_156_25_MHZ] = { - [TYPE_USXGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &usxgmii_156_25_no_ssc_rx_ln_vals, - }, - }, - }, + .rx_ln_vals_tbl = { + .entries = cdns_rx_ln_vals_entries, + .num_entries = ARRAY_SIZE(cdns_rx_ln_vals_entries), }, }; -- GitLab From cb240921ec7b9b5ab9b306a36ace7482ce70d642 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 22 May 2023 19:03:18 +0200 Subject: [PATCH 0134/3445] dt-bindings: phy: rockchip,inno-usb2phy: add rk3588 Add compatible for the USB2 phy in the Rockchip RK3588 SoC. Reviewed-by: Rob Herring Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20230522170324.61349-2-sebastian.reichel@collabora.com Signed-off-by: Vinod Koul --- .../bindings/phy/rockchip,inno-usb2phy.yaml | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/rockchip,inno-usb2phy.yaml b/Documentation/devicetree/bindings/phy/rockchip,inno-usb2phy.yaml index 0d6b8c28be071..5254413137c64 100644 --- a/Documentation/devicetree/bindings/phy/rockchip,inno-usb2phy.yaml +++ b/Documentation/devicetree/bindings/phy/rockchip,inno-usb2phy.yaml @@ -20,6 +20,7 @@ properties: - rockchip,rk3366-usb2phy - rockchip,rk3399-usb2phy - rockchip,rk3568-usb2phy + - rockchip,rk3588-usb2phy - rockchip,rv1108-usb2phy reg: @@ -56,6 +57,14 @@ properties: description: Muxed interrupt for both ports maxItems: 1 + resets: + maxItems: 2 + + reset-names: + items: + - const: phy + - const: apb + rockchip,usbgrf: $ref: /schemas/types.yaml#/definitions/phandle description: @@ -120,15 +129,21 @@ required: - reg - clock-output-names - "#clock-cells" - - host-port - - otg-port + +anyOf: + - required: + - otg-port + - required: + - host-port allOf: - if: properties: compatible: contains: - const: rockchip,rk3568-usb2phy + enum: + - rockchip,rk3568-usb2phy + - rockchip,rk3588-usb2phy then: properties: -- GitLab From 3a7db8e9edefd9e23343d6cb42ab49d2a45e25f3 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 22 May 2023 19:03:19 +0200 Subject: [PATCH 0135/3445] phy: phy-rockchip-inno-usb2: add rk3588 support Add basic support for the USB2 PHY found in the Rockchip RK3588. Co-developed-by: William Wu Signed-off-by: William Wu Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20230522170324.61349-3-sebastian.reichel@collabora.com Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 226 ++++++++++++++++-- 1 file changed, 211 insertions(+), 15 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index a0bc10aa79618..2c4683c67a8ee 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -116,6 +116,12 @@ struct rockchip_chg_det_reg { * @bvalid_det_en: vbus valid rise detection enable register. * @bvalid_det_st: vbus valid rise detection status register. * @bvalid_det_clr: vbus valid rise detection clear register. + * @disfall_en: host disconnect fall edge detection enable. + * @disfall_st: host disconnect fall edge detection state. + * @disfall_clr: host disconnect fall edge detection clear. + * @disrise_en: host disconnect rise edge detection enable. + * @disrise_st: host disconnect rise edge detection state. + * @disrise_clr: host disconnect rise edge detection clear. * @id_det_en: id detection enable register. * @id_det_st: id detection state register. * @id_det_clr: id detection clear register. @@ -133,6 +139,12 @@ struct rockchip_usb2phy_port_cfg { struct usb2phy_reg bvalid_det_en; struct usb2phy_reg bvalid_det_st; struct usb2phy_reg bvalid_det_clr; + struct usb2phy_reg disfall_en; + struct usb2phy_reg disfall_st; + struct usb2phy_reg disfall_clr; + struct usb2phy_reg disrise_en; + struct usb2phy_reg disrise_st; + struct usb2phy_reg disrise_clr; struct usb2phy_reg id_det_en; struct usb2phy_reg id_det_st; struct usb2phy_reg id_det_clr; @@ -168,6 +180,7 @@ struct rockchip_usb2phy_cfg { * @port_id: flag for otg port or host port. * @suspended: phy suspended flag. * @vbus_attached: otg device vbus status. + * @host_disconnect: usb host disconnect status. * @bvalid_irq: IRQ number assigned for vbus valid rise detection. * @id_irq: IRQ number assigned for ID pin detection. * @ls_irq: IRQ number assigned for linestate detection. @@ -187,6 +200,7 @@ struct rockchip_usb2phy_port { unsigned int port_id; bool suspended; bool vbus_attached; + bool host_disconnect; int bvalid_irq; int id_irq; int ls_irq; @@ -405,6 +419,27 @@ static int rockchip_usb2phy_extcon_register(struct rockchip_usb2phy *rphy) return 0; } +static int rockchip_usb2phy_enable_host_disc_irq(struct rockchip_usb2phy *rphy, + struct rockchip_usb2phy_port *rport, + bool en) +{ + int ret; + + ret = property_enable(rphy->grf, &rport->port_cfg->disfall_clr, true); + if (ret) + return ret; + + ret = property_enable(rphy->grf, &rport->port_cfg->disfall_en, en); + if (ret) + return ret; + + ret = property_enable(rphy->grf, &rport->port_cfg->disrise_clr, true); + if (ret) + return ret; + + return property_enable(rphy->grf, &rport->port_cfg->disrise_en, en); +} + static int rockchip_usb2phy_init(struct phy *phy) { struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); @@ -449,6 +484,15 @@ static int rockchip_usb2phy_init(struct phy *phy) dev_dbg(&rport->phy->dev, "mode %d\n", rport->mode); } } else if (rport->port_id == USB2PHY_PORT_HOST) { + if (rport->port_cfg->disfall_en.offset) { + rport->host_disconnect = true; + ret = rockchip_usb2phy_enable_host_disc_irq(rphy, rport, true); + if (ret) { + dev_err(rphy->dev, "failed to enable disconnect irq\n"); + goto out; + } + } + /* clear linestate and enable linestate detect irq */ ret = property_enable(rphy->grf, &rport->port_cfg->ls_det_clr, true); @@ -810,9 +854,7 @@ static void rockchip_usb2phy_sm_work(struct work_struct *work) struct rockchip_usb2phy_port *rport = container_of(work, struct rockchip_usb2phy_port, sm_work.work); struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); - unsigned int sh = rport->port_cfg->utmi_hstdet.bitend - - rport->port_cfg->utmi_hstdet.bitstart + 1; - unsigned int ul, uhd, state; + unsigned int sh, ul, uhd, state; unsigned int ul_mask, uhd_mask; int ret; @@ -822,18 +864,26 @@ static void rockchip_usb2phy_sm_work(struct work_struct *work) if (ret < 0) goto next_schedule; - ret = regmap_read(rphy->grf, rport->port_cfg->utmi_hstdet.offset, &uhd); - if (ret < 0) - goto next_schedule; - - uhd_mask = GENMASK(rport->port_cfg->utmi_hstdet.bitend, - rport->port_cfg->utmi_hstdet.bitstart); ul_mask = GENMASK(rport->port_cfg->utmi_ls.bitend, rport->port_cfg->utmi_ls.bitstart); - /* stitch on utmi_ls and utmi_hstdet as phy state */ - state = ((uhd & uhd_mask) >> rport->port_cfg->utmi_hstdet.bitstart) | - (((ul & ul_mask) >> rport->port_cfg->utmi_ls.bitstart) << sh); + if (rport->port_cfg->utmi_hstdet.offset) { + ret = regmap_read(rphy->grf, rport->port_cfg->utmi_hstdet.offset, &uhd); + if (ret < 0) + goto next_schedule; + + uhd_mask = GENMASK(rport->port_cfg->utmi_hstdet.bitend, + rport->port_cfg->utmi_hstdet.bitstart); + + sh = rport->port_cfg->utmi_hstdet.bitend - + rport->port_cfg->utmi_hstdet.bitstart + 1; + /* stitch on utmi_ls and utmi_hstdet as phy state */ + state = ((uhd & uhd_mask) >> rport->port_cfg->utmi_hstdet.bitstart) | + (((ul & ul_mask) >> rport->port_cfg->utmi_ls.bitstart) << sh); + } else { + state = ((ul & ul_mask) >> rport->port_cfg->utmi_ls.bitstart) << 1 | + rport->host_disconnect; + } switch (state) { case PHY_STATE_HS_ONLINE: @@ -966,6 +1016,31 @@ static irqreturn_t rockchip_usb2phy_otg_mux_irq(int irq, void *data) return ret; } +static irqreturn_t rockchip_usb2phy_host_disc_irq(int irq, void *data) +{ + struct rockchip_usb2phy_port *rport = data; + struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); + + if (!property_enabled(rphy->grf, &rport->port_cfg->disfall_st) && + !property_enabled(rphy->grf, &rport->port_cfg->disrise_st)) + return IRQ_NONE; + + mutex_lock(&rport->mutex); + + /* clear disconnect fall or rise detect irq pending status */ + if (property_enabled(rphy->grf, &rport->port_cfg->disfall_st)) { + property_enable(rphy->grf, &rport->port_cfg->disfall_clr, true); + rport->host_disconnect = false; + } else if (property_enabled(rphy->grf, &rport->port_cfg->disrise_st)) { + property_enable(rphy->grf, &rport->port_cfg->disrise_clr, true); + rport->host_disconnect = true; + } + + mutex_unlock(&rport->mutex); + + return IRQ_HANDLED; +} + static irqreturn_t rockchip_usb2phy_irq(int irq, void *data) { struct rockchip_usb2phy *rphy = data; @@ -978,6 +1053,10 @@ static irqreturn_t rockchip_usb2phy_irq(int irq, void *data) if (!rport->phy) continue; + if (rport->port_id == USB2PHY_PORT_HOST && + rport->port_cfg->disfall_en.offset) + ret |= rockchip_usb2phy_host_disc_irq(irq, rport); + switch (rport->port_id) { case USB2PHY_PORT_OTG: if (rport->mode != USB_DR_MODE_HOST && @@ -1233,7 +1312,7 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) } /* support address_cells=2 */ - if (reg == 0) { + if (of_property_count_u32_elems(np, "reg") > 2 && reg == 0) { if (of_property_read_u32_index(np, "reg", 1, ®)) { dev_err(dev, "the reg property is not assigned in %pOFn node\n", np); @@ -1254,14 +1333,14 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) /* find out a proper config which can be matched with dt. */ index = 0; - while (phy_cfgs[index].reg) { + do { if (phy_cfgs[index].reg == reg) { rphy->phy_cfg = &phy_cfgs[index]; break; } ++index; - } + } while (phy_cfgs[index].reg); if (!rphy->phy_cfg) { dev_err(dev, "no phy-config can be matched with %pOFn node\n", @@ -1664,6 +1743,122 @@ static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = { { /* sentinel */ } }; +static const struct rockchip_usb2phy_cfg rk3588_phy_cfgs[] = { + { + .reg = 0x0000, + .num_ports = 1, + .clkout_ctl = { 0x0000, 0, 0, 1, 0 }, + .port_cfgs = { + [USB2PHY_PORT_OTG] = { + .phy_sus = { 0x000c, 11, 11, 0, 1 }, + .bvalid_det_en = { 0x0080, 1, 1, 0, 1 }, + .bvalid_det_st = { 0x0084, 1, 1, 0, 1 }, + .bvalid_det_clr = { 0x0088, 1, 1, 0, 1 }, + .ls_det_en = { 0x0080, 0, 0, 0, 1 }, + .ls_det_st = { 0x0084, 0, 0, 0, 1 }, + .ls_det_clr = { 0x0088, 0, 0, 0, 1 }, + .disfall_en = { 0x0080, 6, 6, 0, 1 }, + .disfall_st = { 0x0084, 6, 6, 0, 1 }, + .disfall_clr = { 0x0088, 6, 6, 0, 1 }, + .disrise_en = { 0x0080, 5, 5, 0, 1 }, + .disrise_st = { 0x0084, 5, 5, 0, 1 }, + .disrise_clr = { 0x0088, 5, 5, 0, 1 }, + .utmi_avalid = { 0x00c0, 7, 7, 0, 1 }, + .utmi_bvalid = { 0x00c0, 6, 6, 0, 1 }, + .utmi_ls = { 0x00c0, 10, 9, 0, 1 }, + } + }, + .chg_det = { + .cp_det = { 0x00c0, 0, 0, 0, 1 }, + .dcp_det = { 0x00c0, 0, 0, 0, 1 }, + .dp_det = { 0x00c0, 1, 1, 1, 0 }, + .idm_sink_en = { 0x0008, 5, 5, 1, 0 }, + .idp_sink_en = { 0x0008, 5, 5, 0, 1 }, + .idp_src_en = { 0x0008, 14, 14, 0, 1 }, + .rdm_pdwn_en = { 0x0008, 14, 14, 0, 1 }, + .vdm_src_en = { 0x0008, 7, 6, 0, 3 }, + .vdp_src_en = { 0x0008, 7, 6, 0, 3 }, + }, + }, + { + .reg = 0x4000, + .num_ports = 1, + .clkout_ctl = { 0x0000, 0, 0, 1, 0 }, + .port_cfgs = { + [USB2PHY_PORT_OTG] = { + .phy_sus = { 0x000c, 11, 11, 0, 1 }, + .bvalid_det_en = { 0x0080, 1, 1, 0, 1 }, + .bvalid_det_st = { 0x0084, 1, 1, 0, 1 }, + .bvalid_det_clr = { 0x0088, 1, 1, 0, 1 }, + .ls_det_en = { 0x0080, 0, 0, 0, 1 }, + .ls_det_st = { 0x0084, 0, 0, 0, 1 }, + .ls_det_clr = { 0x0088, 0, 0, 0, 1 }, + .disfall_en = { 0x0080, 6, 6, 0, 1 }, + .disfall_st = { 0x0084, 6, 6, 0, 1 }, + .disfall_clr = { 0x0088, 6, 6, 0, 1 }, + .disrise_en = { 0x0080, 5, 5, 0, 1 }, + .disrise_st = { 0x0084, 5, 5, 0, 1 }, + .disrise_clr = { 0x0088, 5, 5, 0, 1 }, + .utmi_avalid = { 0x00c0, 7, 7, 0, 1 }, + .utmi_bvalid = { 0x00c0, 6, 6, 0, 1 }, + .utmi_ls = { 0x00c0, 10, 9, 0, 1 }, + } + }, + .chg_det = { + .cp_det = { 0x00c0, 0, 0, 0, 1 }, + .dcp_det = { 0x00c0, 0, 0, 0, 1 }, + .dp_det = { 0x00c0, 1, 1, 1, 0 }, + .idm_sink_en = { 0x0008, 5, 5, 1, 0 }, + .idp_sink_en = { 0x0008, 5, 5, 0, 1 }, + .idp_src_en = { 0x0008, 14, 14, 0, 1 }, + .rdm_pdwn_en = { 0x0008, 14, 14, 0, 1 }, + .vdm_src_en = { 0x0008, 7, 6, 0, 3 }, + .vdp_src_en = { 0x0008, 7, 6, 0, 3 }, + }, + }, + { + .reg = 0x8000, + .num_ports = 1, + .clkout_ctl = { 0x0000, 0, 0, 1, 0 }, + .port_cfgs = { + [USB2PHY_PORT_HOST] = { + .phy_sus = { 0x0008, 2, 2, 0, 1 }, + .ls_det_en = { 0x0080, 0, 0, 0, 1 }, + .ls_det_st = { 0x0084, 0, 0, 0, 1 }, + .ls_det_clr = { 0x0088, 0, 0, 0, 1 }, + .disfall_en = { 0x0080, 6, 6, 0, 1 }, + .disfall_st = { 0x0084, 6, 6, 0, 1 }, + .disfall_clr = { 0x0088, 6, 6, 0, 1 }, + .disrise_en = { 0x0080, 5, 5, 0, 1 }, + .disrise_st = { 0x0084, 5, 5, 0, 1 }, + .disrise_clr = { 0x0088, 5, 5, 0, 1 }, + .utmi_ls = { 0x00c0, 10, 9, 0, 1 }, + } + }, + }, + { + .reg = 0xc000, + .num_ports = 1, + .clkout_ctl = { 0x0000, 0, 0, 1, 0 }, + .port_cfgs = { + [USB2PHY_PORT_HOST] = { + .phy_sus = { 0x0008, 2, 2, 0, 1 }, + .ls_det_en = { 0x0080, 0, 0, 0, 1 }, + .ls_det_st = { 0x0084, 0, 0, 0, 1 }, + .ls_det_clr = { 0x0088, 0, 0, 0, 1 }, + .disfall_en = { 0x0080, 6, 6, 0, 1 }, + .disfall_st = { 0x0084, 6, 6, 0, 1 }, + .disfall_clr = { 0x0088, 6, 6, 0, 1 }, + .disrise_en = { 0x0080, 5, 5, 0, 1 }, + .disrise_st = { 0x0084, 5, 5, 0, 1 }, + .disrise_clr = { 0x0088, 5, 5, 0, 1 }, + .utmi_ls = { 0x00c0, 10, 9, 0, 1 }, + } + }, + }, + { /* sentinel */ } +}; + static const struct rockchip_usb2phy_cfg rv1108_phy_cfgs[] = { { .reg = 0x100, @@ -1714,6 +1909,7 @@ static const struct of_device_id rockchip_usb2phy_dt_match[] = { { .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs }, { .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs }, { .compatible = "rockchip,rk3568-usb2phy", .data = &rk3568_phy_cfgs }, + { .compatible = "rockchip,rk3588-usb2phy", .data = &rk3588_phy_cfgs }, { .compatible = "rockchip,rv1108-usb2phy", .data = &rv1108_phy_cfgs }, {} }; -- GitLab From 76d58ee8b8af5867ad2baa8e5eab781b20ddc488 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 22 May 2023 19:03:20 +0200 Subject: [PATCH 0136/3445] phy: phy-rockchip-inno-usb2: add reset support Add reset handling support, which is needed for proper operation with RK3588. Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20230522170324.61349-4-sebastian.reichel@collabora.com Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index 2c4683c67a8ee..101b46939f0b6 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -223,6 +224,7 @@ struct rockchip_usb2phy_port { * @clk: clock struct of phy input clk. * @clk480m: clock struct of phy output clk. * @clk480m_hw: clock struct of phy output clk management. + * @phy_reset: phy reset control. * @chg_state: states involved in USB charger detection. * @chg_type: USB charger types. * @dcd_retries: The retry count used to track Data contact @@ -239,6 +241,7 @@ struct rockchip_usb2phy { struct clk *clk; struct clk *clk480m; struct clk_hw clk480m_hw; + struct reset_control *phy_reset; enum usb_chg_state chg_state; enum power_supply_type chg_type; u8 dcd_retries; @@ -280,6 +283,25 @@ static inline bool property_enabled(struct regmap *base, return tmp != reg->disable; } +static int rockchip_usb2phy_reset(struct rockchip_usb2phy *rphy) +{ + int ret; + + ret = reset_control_assert(rphy->phy_reset); + if (ret) + return ret; + + udelay(10); + + ret = reset_control_deassert(rphy->phy_reset); + if (ret) + return ret; + + usleep_range(100, 200); + + return 0; +} + static int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw) { struct rockchip_usb2phy *rphy = @@ -534,6 +556,18 @@ static int rockchip_usb2phy_power_on(struct phy *phy) return ret; } + /* + * For rk3588, it needs to reset phy when exit from + * suspend mode with common_on_n 1'b1(aka REFCLK_LOGIC, + * Bias, and PLL blocks are powered down) for lower + * power consumption. If you don't want to reset phy, + * please keep the common_on_n 1'b0 to set these blocks + * remain powered. + */ + ret = rockchip_usb2phy_reset(rphy); + if (ret) + return ret; + /* waiting for the utmi_clk to become stable */ usleep_range(1500, 2000); @@ -1348,6 +1382,10 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) return -EINVAL; } + rphy->phy_reset = devm_reset_control_get_optional(dev, "phy"); + if (IS_ERR(rphy->phy_reset)) + return PTR_ERR(rphy->phy_reset); + rphy->clk = of_clk_get_by_name(np, "phyclk"); if (!IS_ERR(rphy->clk)) { clk_prepare_enable(rphy->clk); -- GitLab From 5ae6224bb1cd948dad751016d1dfc4196e628eeb Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 22 May 2023 19:03:21 +0200 Subject: [PATCH 0137/3445] phy: phy-rockchip-inno-usb2: add rk3588 phy tuning support On RK3588 some registers need to be tweaked to support waking up from suspend when a USB device is plugged into a port from a suspended PHY. Without this change USB devices only work when they are plugged at boot time. Apart from that it optimizes settings to avoid devices toggling between fullspeed and highspeed mode. Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20230522170324.61349-5-sebastian.reichel@collabora.com Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index 101b46939f0b6..aa8c55609c0db 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -33,6 +33,8 @@ #define SCHEDULE_DELAY (60 * HZ) #define OTG_SCHEDULE_DELAY (2 * HZ) +struct rockchip_usb2phy; + enum rockchip_usb2phy_port_id { USB2PHY_PORT_OTG, USB2PHY_PORT_HOST, @@ -163,6 +165,7 @@ struct rockchip_usb2phy_port_cfg { * struct rockchip_usb2phy_cfg - usb-phy configuration. * @reg: the address offset of grf for usb-phy config. * @num_ports: specify how many ports that the phy has. + * @phy_tuning: phy default parameters tuning. * @clkout_ctl: keep on/turn off output clk of phy. * @port_cfgs: usb-phy port configurations. * @chg_det: charger detection registers. @@ -170,6 +173,7 @@ struct rockchip_usb2phy_port_cfg { struct rockchip_usb2phy_cfg { unsigned int reg; unsigned int num_ports; + int (*phy_tuning)(struct rockchip_usb2phy *rphy); struct usb2phy_reg clkout_ctl; const struct rockchip_usb2phy_port_cfg port_cfgs[USB2PHY_NUM_PORTS]; const struct rockchip_chg_det_reg chg_det; @@ -1400,6 +1404,12 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) goto disable_clks; } + if (rphy->phy_cfg->phy_tuning) { + ret = rphy->phy_cfg->phy_tuning(rphy); + if (ret) + goto disable_clks; + } + index = 0; for_each_available_child_of_node(np, child_np) { struct rockchip_usb2phy_port *rport = &rphy->ports[index]; @@ -1468,6 +1478,55 @@ disable_clks: return ret; } +static int rk3588_usb2phy_tuning(struct rockchip_usb2phy *rphy) +{ + int ret; + bool usb3otg = false; + /* + * utmi_termselect = 1'b1 (en FS terminations) + * utmi_xcvrselect = 2'b01 (FS transceiver) + */ + int suspend_cfg = 0x14; + + if (rphy->phy_cfg->reg == 0x0000 || rphy->phy_cfg->reg == 0x4000) { + /* USB2 config for USB3_0 and USB3_1 */ + suspend_cfg |= 0x01; /* utmi_opmode = 2'b01 (no-driving) */ + usb3otg = true; + } else if (rphy->phy_cfg->reg == 0x8000 || rphy->phy_cfg->reg == 0xc000) { + /* USB2 config for USB2_0 and USB2_1 */ + suspend_cfg |= 0x00; /* utmi_opmode = 2'b00 (normal) */ + } else { + return -EINVAL; + } + + /* Deassert SIDDQ to power on analog block */ + ret = regmap_write(rphy->grf, 0x0008, GENMASK(29, 29) | 0x0000); + if (ret) + return ret; + + /* Do reset after exit IDDQ mode */ + ret = rockchip_usb2phy_reset(rphy); + if (ret) + return ret; + + /* suspend configuration */ + ret |= regmap_write(rphy->grf, 0x000c, GENMASK(20, 16) | suspend_cfg); + + /* HS DC Voltage Level Adjustment 4'b1001 : +5.89% */ + ret |= regmap_write(rphy->grf, 0x0004, GENMASK(27, 24) | 0x0900); + + /* HS Transmitter Pre-Emphasis Current Control 2'b10 : 2x */ + ret |= regmap_write(rphy->grf, 0x0008, GENMASK(20, 19) | 0x0010); + + if (!usb3otg) + return ret; + + /* Pullup iddig pin for USB3_0 OTG mode */ + ret |= regmap_write(rphy->grf, 0x0010, GENMASK(17, 16) | 0x0003); + + return ret; +} + static const struct rockchip_usb2phy_cfg rk3228_phy_cfgs[] = { { .reg = 0x760, @@ -1785,6 +1844,7 @@ static const struct rockchip_usb2phy_cfg rk3588_phy_cfgs[] = { { .reg = 0x0000, .num_ports = 1, + .phy_tuning = rk3588_usb2phy_tuning, .clkout_ctl = { 0x0000, 0, 0, 1, 0 }, .port_cfgs = { [USB2PHY_PORT_OTG] = { @@ -1821,6 +1881,7 @@ static const struct rockchip_usb2phy_cfg rk3588_phy_cfgs[] = { { .reg = 0x4000, .num_ports = 1, + .phy_tuning = rk3588_usb2phy_tuning, .clkout_ctl = { 0x0000, 0, 0, 1, 0 }, .port_cfgs = { [USB2PHY_PORT_OTG] = { @@ -1857,6 +1918,7 @@ static const struct rockchip_usb2phy_cfg rk3588_phy_cfgs[] = { { .reg = 0x8000, .num_ports = 1, + .phy_tuning = rk3588_usb2phy_tuning, .clkout_ctl = { 0x0000, 0, 0, 1, 0 }, .port_cfgs = { [USB2PHY_PORT_HOST] = { @@ -1877,6 +1939,7 @@ static const struct rockchip_usb2phy_cfg rk3588_phy_cfgs[] = { { .reg = 0xc000, .num_ports = 1, + .phy_tuning = rk3588_usb2phy_tuning, .clkout_ctl = { 0x0000, 0, 0, 1, 0 }, .port_cfgs = { [USB2PHY_PORT_HOST] = { -- GitLab From b43511233c6e34b9c0d9a55e41b078d10e7d9ea6 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 22 May 2023 19:03:22 +0200 Subject: [PATCH 0138/3445] phy: phy-rockchip-inno-usb2: simplify phy clock handling Simplify phyclk handling by using devm_clk_get_optional_enabled to acquire and enable the optional clock. This also fixes a resource leak in driver remove path and adds proper error handling. Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20230522170324.61349-6-sebastian.reichel@collabora.com Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index aa8c55609c0db..1cf84869e78b2 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -1390,24 +1390,22 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) if (IS_ERR(rphy->phy_reset)) return PTR_ERR(rphy->phy_reset); - rphy->clk = of_clk_get_by_name(np, "phyclk"); - if (!IS_ERR(rphy->clk)) { - clk_prepare_enable(rphy->clk); - } else { - dev_info(&pdev->dev, "no phyclk specified\n"); - rphy->clk = NULL; + rphy->clk = devm_clk_get_optional_enabled(dev, "phyclk"); + if (IS_ERR(rphy->clk)) { + return dev_err_probe(&pdev->dev, PTR_ERR(rphy->clk), + "failed to get phyclk\n"); } ret = rockchip_usb2phy_clk480m_register(rphy); if (ret) { dev_err(dev, "failed to register 480m output clock\n"); - goto disable_clks; + return ret; } if (rphy->phy_cfg->phy_tuning) { ret = rphy->phy_cfg->phy_tuning(rphy); if (ret) - goto disable_clks; + return ret; } index = 0; @@ -1470,11 +1468,6 @@ next_child: put_child: of_node_put(child_np); -disable_clks: - if (rphy->clk) { - clk_disable_unprepare(rphy->clk); - clk_put(rphy->clk); - } return ret; } -- GitLab From 89e1570ad2121d4a5d5796e9f75ae3b0fdf73bf6 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 22 May 2023 19:03:23 +0200 Subject: [PATCH 0139/3445] phy: phy-rockchip-inno-usb2: simplify getting match data Simplify the code by directly getting the match data via device_get_match_data() instead of open coding its functionality. Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20230522170324.61349-7-sebastian.reichel@collabora.com Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index 1cf84869e78b2..f5c30f117cbad 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -1305,7 +1305,6 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) struct phy_provider *provider; struct rockchip_usb2phy *rphy; const struct rockchip_usb2phy_cfg *phy_cfgs; - const struct of_device_id *match; unsigned int reg; int index, ret; @@ -1313,12 +1312,6 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) if (!rphy) return -ENOMEM; - match = of_match_device(dev->driver->of_match_table, dev); - if (!match || !match->data) { - dev_err(dev, "phy configs are not assigned!\n"); - return -EINVAL; - } - if (!dev->parent || !dev->parent->of_node) { rphy->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,usbgrf"); if (IS_ERR(rphy->grf)) { @@ -1359,12 +1352,15 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) } rphy->dev = dev; - phy_cfgs = match->data; + phy_cfgs = device_get_match_data(dev); rphy->chg_state = USB_CHG_STATE_UNDEFINED; rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN; rphy->irq = platform_get_irq_optional(pdev, 0); platform_set_drvdata(pdev, rphy); + if (!phy_cfgs) + return dev_err_probe(dev, -EINVAL, "phy configs are not assigned!\n"); + ret = rockchip_usb2phy_extcon_register(rphy); if (ret) return ret; -- GitLab From b3a379936335c7e6e2e6cc3188fe1e8bde222290 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 22 May 2023 19:03:24 +0200 Subject: [PATCH 0140/3445] phy: phy-rockchip-inno-usb2: improve error message Printing the OF node is not useful, since we get the same information from the device context. Instead print the reg address, that could not be found. Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20230522170324.61349-8-sebastian.reichel@collabora.com Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index f5c30f117cbad..b982c3f0d4b56 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -1377,8 +1377,7 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) } while (phy_cfgs[index].reg); if (!rphy->phy_cfg) { - dev_err(dev, "no phy-config can be matched with %pOFn node\n", - np); + dev_err(dev, "could not find phy config for reg=0x%08x\n", reg); return -EINVAL; } -- GitLab From fe71437884fd79cc6bd11b13a89642f894dc7361 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 31 May 2023 05:34:11 +0300 Subject: [PATCH 0141/3445] dt-bindings: phy: qcom,sc7180-qmp-usb3-dp-phy: add sm8150 USB+DP PHY Add bindings for sm8150 USB+DP PHY. These bindings follow the older style as this is a quick conversion to simplify further driver cleanup. Acked-by: Rob Herring Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230531023415.1209301-2-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/qcom,sc7180-qmp-usb3-dp-phy.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,sc7180-qmp-usb3-dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc7180-qmp-usb3-dp-phy.yaml index d307343388888..3c97289383917 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc7180-qmp-usb3-dp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc7180-qmp-usb3-dp-phy.yaml @@ -24,6 +24,7 @@ properties: - qcom,sc7180-qmp-usb3-dp-phy - qcom,sc8180x-qmp-usb3-dp-phy - qcom,sdm845-qmp-usb3-dp-phy + - qcom,sm8150-qmp-usb3-dp-phy - qcom,sm8250-qmp-usb3-dp-phy - items: - enum: @@ -196,6 +197,7 @@ allOf: compatible: enum: - qcom,sc8180x-qmp-usb3-dp-phy + - qcom,sm8150-qmp-usb3-dp-phy then: properties: clocks: -- GitLab From 757a788c17d258ab88343262709b71e21c47ba20 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 31 May 2023 05:34:12 +0300 Subject: [PATCH 0142/3445] phy: qcom-qmp-combo: add support for the USB+DP PHY on SM8150 platform SM8150 and SC8180X are close relatives. Reuse sc8180x data to support USB+DP combo PHY on SM8150 platform. Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230531023415.1209301-3-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index bebce8c591a30..d4f271b3c2117 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -3618,6 +3618,10 @@ static const struct of_device_id qmp_combo_of_match_table[] = { .compatible = "qcom,sm6350-qmp-usb3-dp-phy", .data = &sm6350_usb3dpphy_cfg, }, + { + .compatible = "qcom,sm8150-qmp-usb3-dp-phy", + .data = &sc8180x_usb3dpphy_cfg, + }, { .compatible = "qcom,sm8250-qmp-usb3-dp-phy", .data = &sm8250_usb3dpphy_cfg, -- GitLab From ff4cb058e0abfba5e32776ae8c8aa48ac2d1634b Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 31 May 2023 05:34:14 +0300 Subject: [PATCH 0143/3445] dt-bindings: phy: qcom,msm8996-qmp-usb3-phy: drop legacy bindings The qcom,msm8996-qmp-usb3-phy.yaml defines bindings for several PHYs which predate USB -> USB+DP migration. Now as sm8150 has been migrated, drop the legacy bindings completely. No device trees use them anymore. Newer USB+DP bindings should use combo bindings from the beginning. Signed-off-by: Dmitry Baryshkov Acked-by: Rob Herring Link: https://lore.kernel.org/r/20230531023415.1209301-5-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- .../phy/qcom,msm8996-qmp-usb3-phy.yaml | 80 ------------------- 1 file changed, 80 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/qcom,msm8996-qmp-usb3-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,msm8996-qmp-usb3-phy.yaml index 4c96dab5b9e36..827109d370415 100644 --- a/Documentation/devicetree/bindings/phy/qcom,msm8996-qmp-usb3-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,msm8996-qmp-usb3-phy.yaml @@ -23,25 +23,16 @@ properties: - qcom,ipq8074-qmp-usb3-phy - qcom,msm8996-qmp-usb3-phy - qcom,msm8998-qmp-usb3-phy - - qcom,sc7180-qmp-usb3-phy - - qcom,sc8180x-qmp-usb3-phy - - qcom,sdm845-qmp-usb3-phy - qcom,sdm845-qmp-usb3-uni-phy - qcom,sdx55-qmp-usb3-uni-phy - qcom,sdx65-qmp-usb3-uni-phy - - qcom,sm8150-qmp-usb3-phy - qcom,sm8150-qmp-usb3-uni-phy - - qcom,sm8250-qmp-usb3-phy - qcom,sm8250-qmp-usb3-uni-phy - - qcom,sm8350-qmp-usb3-phy - qcom,sm8350-qmp-usb3-uni-phy - - qcom,sm8450-qmp-usb3-phy reg: - minItems: 1 items: - description: serdes - - description: DP_COM "#address-cells": enum: [ 1, 2 ] @@ -126,28 +117,6 @@ required: additionalProperties: false allOf: - - if: - properties: - compatible: - contains: - enum: - - qcom,sc7180-qmp-usb3-phy - then: - properties: - clocks: - maxItems: 4 - clock-names: - items: - - const: aux - - const: cfg_ahb - - const: ref - - const: com_aux - resets: - maxItems: 1 - reset-names: - items: - - const: phy - - if: properties: compatible: @@ -202,7 +171,6 @@ allOf: compatible: contains: enum: - - qcom,sm8150-qmp-usb3-phy - qcom,sm8150-qmp-usb3-uni-phy - qcom,sm8250-qmp-usb3-uni-phy - qcom,sm8350-qmp-usb3-uni-phy @@ -223,51 +191,6 @@ allOf: - const: phy - const: common - - if: - properties: - compatible: - contains: - enum: - - qcom,sm8250-qmp-usb3-phy - - qcom,sm8350-qmp-usb3-phy - then: - properties: - clocks: - maxItems: 3 - clock-names: - items: - - const: aux - - const: ref_clk_src - - const: com_aux - resets: - maxItems: 2 - reset-names: - items: - - const: phy - - const: common - - - if: - properties: - compatible: - contains: - enum: - - qcom,sdm845-qmp-usb3-phy - - qcom,sm8150-qmp-usb3-phy - - qcom,sm8350-qmp-usb3-phy - - qcom,sm8450-qmp-usb3-phy - then: - patternProperties: - "^phy@[0-9a-f]+$": - properties: - reg: - items: - - description: TX lane 1 - - description: RX lane 1 - - description: PCS - - description: TX lane 2 - - description: RX lane 2 - - description: PCS_MISC - - if: properties: compatible: @@ -293,12 +216,9 @@ allOf: enum: - qcom,ipq6018-qmp-usb3-phy - qcom,ipq8074-qmp-usb3-phy - - qcom,sc7180-qmp-usb3-phy - - qcom,sc8180x-qmp-usb3-phy - qcom,sdx55-qmp-usb3-uni-phy - qcom,sdx65-qmp-usb3-uni-phy - qcom,sm8150-qmp-usb3-uni-phy - - qcom,sm8250-qmp-usb3-phy then: patternProperties: "^phy@[0-9a-f]+$": -- GitLab From e464a3180a43b6596bd267f9f274e1793bfb8150 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 31 May 2023 05:34:15 +0300 Subject: [PATCH 0144/3445] phy: qcom-qmp-usb: split off the legacy USB+dp_com support When adding support for some of the platforms (sc7180, sc8180x, sdm845, sm8[1234]50), we added USB PHYs for the combo USB+DP QMP PHYs. Now all such usecases were migrated to use USB+DP Combo driver. To simplify the qcom-qmp-usb PHY driver split the legacy USB+dp_com support into a separate driver. Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230531023415.1209301-6-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/Kconfig | 10 + drivers/phy/qualcomm/Makefile | 1 + .../phy/qualcomm/phy-qcom-qmp-usb-legacy.c | 1407 +++++++++++++++++ drivers/phy/qualcomm/phy-qcom-qmp-usb.c | 556 ------- 4 files changed, 1418 insertions(+), 556 deletions(-) create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig index 97ca5952e34e3..ced603806375c 100644 --- a/drivers/phy/qualcomm/Kconfig +++ b/drivers/phy/qualcomm/Kconfig @@ -102,6 +102,16 @@ config PHY_QCOM_QMP_USB Enable this to support the QMP USB PHY transceiver that is used with USB3 controllers on Qualcomm chips. +config PHY_QCOM_QMP_USB_LEGACY + tristate "Qualcomm QMP legacy USB PHY Driver" + select GENERIC_PHY + default n + help + Enable this legacy driver to support the QMP USB+DisplayPort Combo + PHY transceivers working only in USB3 mode on Qualcomm chips. This + driver exists only for compatibility with older device trees, + existing users have been migrated to PHY_QCOM_QMP_COMBO driver. + endif # PHY_QCOM_QMP config PHY_QCOM_QUSB2 diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile index b030858e0f8d6..df945811d9d35 100644 --- a/drivers/phy/qualcomm/Makefile +++ b/drivers/phy/qualcomm/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_PHY_QCOM_QMP_PCIE) += phy-qcom-qmp-pcie.o obj-$(CONFIG_PHY_QCOM_QMP_PCIE_8996) += phy-qcom-qmp-pcie-msm8996.o obj-$(CONFIG_PHY_QCOM_QMP_UFS) += phy-qcom-qmp-ufs.o obj-$(CONFIG_PHY_QCOM_QMP_USB) += phy-qcom-qmp-usb.o +obj-$(CONFIG_PHY_QCOM_QMP_USB_LEGACY) += phy-qcom-qmp-usb-legacy.o obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o obj-$(CONFIG_PHY_QCOM_SNPS_EUSB2) += phy-qcom-snps-eusb2.o diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c new file mode 100644 index 0000000000000..cf466f6df94d7 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c @@ -0,0 +1,1407 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "phy-qcom-qmp.h" +#include "phy-qcom-qmp-pcs-misc-v3.h" +#include "phy-qcom-qmp-pcs-usb-v4.h" +#include "phy-qcom-qmp-pcs-usb-v5.h" + +/* QPHY_SW_RESET bit */ +#define SW_RESET BIT(0) +/* QPHY_POWER_DOWN_CONTROL */ +#define SW_PWRDN BIT(0) +/* QPHY_START_CONTROL bits */ +#define SERDES_START BIT(0) +#define PCS_START BIT(1) +/* QPHY_PCS_STATUS bit */ +#define PHYSTATUS BIT(6) + +/* QPHY_V3_DP_COM_RESET_OVRD_CTRL register bits */ +/* DP PHY soft reset */ +#define SW_DPPHY_RESET BIT(0) +/* mux to select DP PHY reset control, 0:HW control, 1: software reset */ +#define SW_DPPHY_RESET_MUX BIT(1) +/* USB3 PHY soft reset */ +#define SW_USB3PHY_RESET BIT(2) +/* mux to select USB3 PHY reset control, 0:HW control, 1: software reset */ +#define SW_USB3PHY_RESET_MUX BIT(3) + +/* QPHY_V3_DP_COM_PHY_MODE_CTRL register bits */ +#define USB3_MODE BIT(0) /* enables USB3 mode */ +#define DP_MODE BIT(1) /* enables DP mode */ + +/* QPHY_PCS_AUTONOMOUS_MODE_CTRL register bits */ +#define ARCVR_DTCT_EN BIT(0) +#define ALFPS_DTCT_EN BIT(1) +#define ARCVR_DTCT_EVENT_SEL BIT(4) + +/* QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR register bits */ +#define IRQ_CLEAR BIT(0) + +/* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */ +#define CLAMP_EN BIT(0) /* enables i/o clamp_n */ + +#define PHY_INIT_COMPLETE_TIMEOUT 10000 + +struct qmp_phy_init_tbl { + unsigned int offset; + unsigned int val; + /* + * mask of lanes for which this register is written + * for cases when second lane needs different values + */ + u8 lane_mask; +}; + +#define QMP_PHY_INIT_CFG(o, v) \ + { \ + .offset = o, \ + .val = v, \ + .lane_mask = 0xff, \ + } + +#define QMP_PHY_INIT_CFG_LANE(o, v, l) \ + { \ + .offset = o, \ + .val = v, \ + .lane_mask = l, \ + } + +/* set of registers with offsets different per-PHY */ +enum qphy_reg_layout { + /* PCS registers */ + QPHY_SW_RESET, + QPHY_START_CTRL, + QPHY_PCS_STATUS, + QPHY_PCS_AUTONOMOUS_MODE_CTRL, + QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR, + QPHY_PCS_POWER_DOWN_CONTROL, + /* Keep last to ensure regs_layout arrays are properly initialized */ + QPHY_LAYOUT_SIZE +}; + +static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_SW_RESET] = QPHY_V3_PCS_SW_RESET, + [QPHY_START_CTRL] = QPHY_V3_PCS_START_CONTROL, + [QPHY_PCS_STATUS] = QPHY_V3_PCS_PCS_STATUS, + [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V3_PCS_AUTONOMOUS_MODE_CTRL, + [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V3_PCS_LFPS_RXTERM_IRQ_CLEAR, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V3_PCS_POWER_DOWN_CONTROL, +}; + +static const unsigned int qmp_v4_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_SW_RESET] = QPHY_V4_PCS_SW_RESET, + [QPHY_START_CTRL] = QPHY_V4_PCS_START_CONTROL, + [QPHY_PCS_STATUS] = QPHY_V4_PCS_PCS_STATUS1, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V4_PCS_POWER_DOWN_CONTROL, + + /* In PCS_USB */ + [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V4_PCS_USB3_AUTONOMOUS_MODE_CTRL, + [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V4_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR, +}; + +static const unsigned int qmp_v5_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_SW_RESET] = QPHY_V5_PCS_SW_RESET, + [QPHY_START_CTRL] = QPHY_V5_PCS_START_CONTROL, + [QPHY_PCS_STATUS] = QPHY_V5_PCS_PCS_STATUS1, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V5_PCS_POWER_DOWN_CONTROL, + + /* In PCS_USB */ + [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V5_PCS_USB3_AUTONOMOUS_MODE_CTRL, + [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V5_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR, +}; + +static const struct qmp_phy_init_tbl qmp_v3_usb3_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL2, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START1_MODE0, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START2_MODE0, 0xea), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START3_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xc9), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORECLK_DIV_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0x15), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_CFG, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_BUF_ENABLE, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER1, 0x31), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE1, 0x85), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE2, 0x07), +}; + +static const struct qmp_phy_init_tbl qmp_v3_usb3_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x06), +}; + +static const struct qmp_phy_init_tbl qmp_v3_usb3_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75), +}; + +static const struct qmp_phy_init_tbl qmp_v3_usb3_pcs_tbl[] = { + /* FLL settings */ + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x40), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02), + + /* Lock Det settings */ + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG1, 0xd1), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG2, 0x1f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG3, 0x47), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_POWER_STATE_CONFIG2, 0x1b), + + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0xba), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V1, 0x9f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V2, 0xb7), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V3, 0x4e), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V4, 0x65), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_LS, 0x6b), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V1, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V1, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V2, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V2, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V3, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V3, 0x1d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V4, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V4, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_LS, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_LS, 0x0d), + + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RATE_SLEW_CNTRL, 0x02), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TSYNC_RSYNC_TIME, 0x44), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L, 0x40), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H, 0x00), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME, 0x75), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13), +}; + +static const struct qmp_phy_init_tbl sm8150_usb3_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_PER1, 0x31), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE1_MODE0, 0xde), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE2_MODE0, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE1_MODE1, 0xde), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE2_MODE1, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_BUF_ENABLE, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_IPTRIM, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE1, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE1, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE1, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE1, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START1_MODE0, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE0, 0xea), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_MAP, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START1_MODE1, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE1, 0xea), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE1, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE1_MODE0, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE1_MODE1, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE2_MODE1, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORECLK_DIV_MODE1, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xca), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1e), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xca), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x1e), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_HSCLK_SEL, 0x11), +}; + +static const struct qmp_phy_init_tbl sm8150_usb3_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_TX, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_RX, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_LANE_MODE_1, 0xd5), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_RCV_DETECT_LVL_2, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_PI_QEC_CTRL, 0x20), +}; + +static const struct qmp_phy_init_tbl sm8150_usb3_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_GAIN, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_FO_GAIN, 0x2f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_COUNT_LOW, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_PI_CONTROLS, 0x99), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_THRESH1, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_THRESH2, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_GAIN1, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_GAIN2, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_VGA_CAL_CNTRL1, 0x54), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_VGA_CAL_CNTRL2, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4a), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_LOW, 0xc0), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_HIGH, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_CNTRL, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_DEGLITCH_CNTRL, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_LOW, 0xbf), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH, 0xbf), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH2, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH3, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH4, 0x94), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_LOW, 0xdc), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH, 0xdc), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH2, 0x5c), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH3, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH4, 0xb3), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_DFE_EN_TIMER, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_AUX_DATA_TCOARSE_TFINE, 0xa0), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_DCC_CTRL1, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_GM_CAL, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_VTH_CODE, 0x10), +}; + +static const struct qmp_phy_init_tbl sm8150_usb3_pcs_tbl[] = { + /* Lock Det settings */ + QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG1, 0xd0), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG2, 0x07), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG6, 0x13), + + QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x21), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_SIGDET_LVL, 0xaa), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_CDR_RESET_TIME, 0x0a), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG1, 0x88), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG2, 0x13), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCS_TX_RX_CONFIG, 0x0c), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG1, 0x4b), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG5, 0x10), +}; + +static const struct qmp_phy_init_tbl sm8150_usb3_pcs_usb_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V4_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07), +}; + +static const struct qmp_phy_init_tbl sm8250_usb3_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_TX, 0x60), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_RX, 0x60), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_OFFSET_TX, 0x11), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_OFFSET_RX, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_LANE_MODE_1, 0xd5), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_RCV_DETECT_LVL_2, 0x12), + QMP_PHY_INIT_CFG_LANE(QSERDES_V4_TX_PI_QEC_CTRL, 0x40, 1), + QMP_PHY_INIT_CFG_LANE(QSERDES_V4_TX_PI_QEC_CTRL, 0x54, 2), +}; + +static const struct qmp_phy_init_tbl sm8250_usb3_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_GAIN, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_FO_GAIN, 0x2f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_COUNT_LOW, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_PI_CONTROLS, 0x99), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_THRESH1, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_THRESH2, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_GAIN1, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_GAIN2, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_VGA_CAL_CNTRL1, 0x54), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_VGA_CAL_CNTRL2, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4a), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_LOW, 0xc0), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_HIGH, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_CNTRL, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_DEGLITCH_CNTRL, 0x0e), + QMP_PHY_INIT_CFG_LANE(QSERDES_V4_RX_RX_MODE_00_LOW, 0xff, 1), + QMP_PHY_INIT_CFG_LANE(QSERDES_V4_RX_RX_MODE_00_LOW, 0x7f, 2), + QMP_PHY_INIT_CFG_LANE(QSERDES_V4_RX_RX_MODE_00_HIGH, 0x7f, 1), + QMP_PHY_INIT_CFG_LANE(QSERDES_V4_RX_RX_MODE_00_HIGH, 0xff, 2), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH2, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH3, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH4, 0x97), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_LOW, 0xdc), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH, 0xdc), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH2, 0x5c), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH3, 0x7b), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH4, 0xb4), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_DFE_EN_TIMER, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_AUX_DATA_TCOARSE_TFINE, 0xa0), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_DCC_CTRL1, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_GM_CAL, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_VTH_CODE, 0x10), +}; + +static const struct qmp_phy_init_tbl sm8250_usb3_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG1, 0xd0), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG2, 0x07), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG3, 0x20), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG6, 0x13), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x21), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_SIGDET_LVL, 0xa9), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_CDR_RESET_TIME, 0x0a), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG1, 0x88), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG2, 0x13), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCS_TX_RX_CONFIG, 0x0c), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG1, 0x4b), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG5, 0x10), +}; + +static const struct qmp_phy_init_tbl sm8250_usb3_pcs_usb_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V4_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07), +}; + +static const struct qmp_phy_init_tbl sm8350_usb3_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_TX, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_RX, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_TX, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_1, 0x35), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_3, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_4, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_5, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_RCV_DETECT_LVL_2, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_PI_QEC_CTRL, 0x21), +}; + +static const struct qmp_phy_init_tbl sm8350_usb3_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FO_GAIN, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SO_GAIN, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_FO_GAIN, 0x2f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_LOW, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_PI_CONTROLS, 0x99), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_THRESH1, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_THRESH2, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_GAIN1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_GAIN2, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL1, 0x54), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL2, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4a), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_IDAC_TSETTLE_LOW, 0xc0), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_IDAC_TSETTLE_HIGH, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x47), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_CNTRL, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_DEGLITCH_CNTRL, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_LOW, 0xbb), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH, 0x7b), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH2, 0xbb), + QMP_PHY_INIT_CFG_LANE(QSERDES_V5_RX_RX_MODE_00_HIGH3, 0x3d, 1), + QMP_PHY_INIT_CFG_LANE(QSERDES_V5_RX_RX_MODE_00_HIGH3, 0x3c, 2), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH4, 0xdb), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_LOW, 0x64), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH2, 0xd2), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH3, 0x13), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH4, 0xa9), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_DFE_EN_TIMER, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_AUX_DATA_TCOARSE_TFINE, 0xa0), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_DCC_CTRL1, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_GM_CAL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_VTH_CODE, 0x10), +}; + +static const struct qmp_phy_init_tbl sm8350_usb3_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V4_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG1, 0xd0), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG2, 0x07), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG3, 0x20), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG6, 0x13), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x21), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_SIGDET_LVL, 0xaa), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_CDR_RESET_TIME, 0x0a), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG1, 0x88), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG2, 0x13), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCS_TX_RX_CONFIG, 0x0c), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG1, 0x4b), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG5, 0x10), +}; + +static const struct qmp_phy_init_tbl sm8350_usb3_pcs_usb_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_RCVR_DTCT_DLY_U3_L, 0x40), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_RCVR_DTCT_DLY_U3_H, 0x00), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07), +}; + +struct qmp_usb_legacy_offsets { + u16 serdes; + u16 pcs; + u16 pcs_usb; + u16 tx; + u16 rx; +}; + +/* struct qmp_phy_cfg - per-PHY initialization config */ +struct qmp_phy_cfg { + int lanes; + + const struct qmp_usb_legacy_offsets *offsets; + + /* Init sequence for PHY blocks - serdes, tx, rx, pcs */ + const struct qmp_phy_init_tbl *serdes_tbl; + int serdes_tbl_num; + const struct qmp_phy_init_tbl *tx_tbl; + int tx_tbl_num; + const struct qmp_phy_init_tbl *rx_tbl; + int rx_tbl_num; + const struct qmp_phy_init_tbl *pcs_tbl; + int pcs_tbl_num; + const struct qmp_phy_init_tbl *pcs_usb_tbl; + int pcs_usb_tbl_num; + + /* clock ids to be requested */ + const char * const *clk_list; + int num_clks; + /* resets to be requested */ + const char * const *reset_list; + int num_resets; + /* regulators to be requested */ + const char * const *vreg_list; + int num_vregs; + + /* array of registers with different offsets */ + const unsigned int *regs; + + /* Offset from PCS to PCS_USB region */ + unsigned int pcs_usb_offset; +}; + +struct qmp_usb { + struct device *dev; + + const struct qmp_phy_cfg *cfg; + + void __iomem *serdes; + void __iomem *pcs; + void __iomem *pcs_misc; + void __iomem *pcs_usb; + void __iomem *tx; + void __iomem *rx; + void __iomem *tx2; + void __iomem *rx2; + + void __iomem *dp_com; + + struct clk *pipe_clk; + struct clk_bulk_data *clks; + struct reset_control_bulk_data *resets; + struct regulator_bulk_data *vregs; + + enum phy_mode mode; + + struct phy *phy; + + struct clk_fixed_rate pipe_clk_fixed; +}; + +static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val) +{ + u32 reg; + + reg = readl(base + offset); + reg |= val; + writel(reg, base + offset); + + /* ensure that above write is through */ + readl(base + offset); +} + +static inline void qphy_clrbits(void __iomem *base, u32 offset, u32 val) +{ + u32 reg; + + reg = readl(base + offset); + reg &= ~val; + writel(reg, base + offset); + + /* ensure that above write is through */ + readl(base + offset); +} + +/* list of clocks required by phy */ +static const char * const qmp_v3_phy_clk_l[] = { + "aux", "cfg_ahb", "ref", "com_aux", +}; + +static const char * const qmp_v4_ref_phy_clk_l[] = { + "aux", "ref_clk_src", "ref", "com_aux", +}; + +/* the primary usb3 phy on sm8250 doesn't have a ref clock */ +static const char * const qmp_v4_sm8250_usbphy_clk_l[] = { + "aux", "ref_clk_src", "com_aux" +}; + +/* list of resets */ +static const char * const msm8996_usb3phy_reset_l[] = { + "phy", "common", +}; + +static const char * const sc7180_usb3phy_reset_l[] = { + "phy", +}; + +/* list of regulators */ +static const char * const qmp_phy_vreg_l[] = { + "vdda-phy", "vdda-pll", +}; + +static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = { + .lanes = 2, + + .serdes_tbl = qmp_v3_usb3_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl), + .tx_tbl = qmp_v3_usb3_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(qmp_v3_usb3_tx_tbl), + .rx_tbl = qmp_v3_usb3_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(qmp_v3_usb3_rx_tbl), + .pcs_tbl = qmp_v3_usb3_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(qmp_v3_usb3_pcs_tbl), + .clk_list = qmp_v3_phy_clk_l, + .num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l), + .reset_list = msm8996_usb3phy_reset_l, + .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v3_usb3phy_regs_layout, +}; + +static const struct qmp_phy_cfg sc7180_usb3phy_cfg = { + .lanes = 2, + + .serdes_tbl = qmp_v3_usb3_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl), + .tx_tbl = qmp_v3_usb3_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(qmp_v3_usb3_tx_tbl), + .rx_tbl = qmp_v3_usb3_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(qmp_v3_usb3_rx_tbl), + .pcs_tbl = qmp_v3_usb3_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(qmp_v3_usb3_pcs_tbl), + .clk_list = qmp_v3_phy_clk_l, + .num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l), + .reset_list = sc7180_usb3phy_reset_l, + .num_resets = ARRAY_SIZE(sc7180_usb3phy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v3_usb3phy_regs_layout, +}; + +static const struct qmp_phy_cfg sm8150_usb3phy_cfg = { + .lanes = 2, + + .serdes_tbl = sm8150_usb3_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl), + .tx_tbl = sm8150_usb3_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(sm8150_usb3_tx_tbl), + .rx_tbl = sm8150_usb3_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(sm8150_usb3_rx_tbl), + .pcs_tbl = sm8150_usb3_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(sm8150_usb3_pcs_tbl), + .pcs_usb_tbl = sm8150_usb3_pcs_usb_tbl, + .pcs_usb_tbl_num = ARRAY_SIZE(sm8150_usb3_pcs_usb_tbl), + .clk_list = qmp_v4_ref_phy_clk_l, + .num_clks = ARRAY_SIZE(qmp_v4_ref_phy_clk_l), + .reset_list = msm8996_usb3phy_reset_l, + .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v4_usb3phy_regs_layout, + .pcs_usb_offset = 0x300, +}; + +static const struct qmp_phy_cfg sm8250_usb3phy_cfg = { + .lanes = 2, + + .serdes_tbl = sm8150_usb3_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl), + .tx_tbl = sm8250_usb3_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(sm8250_usb3_tx_tbl), + .rx_tbl = sm8250_usb3_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(sm8250_usb3_rx_tbl), + .pcs_tbl = sm8250_usb3_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(sm8250_usb3_pcs_tbl), + .pcs_usb_tbl = sm8250_usb3_pcs_usb_tbl, + .pcs_usb_tbl_num = ARRAY_SIZE(sm8250_usb3_pcs_usb_tbl), + .clk_list = qmp_v4_sm8250_usbphy_clk_l, + .num_clks = ARRAY_SIZE(qmp_v4_sm8250_usbphy_clk_l), + .reset_list = msm8996_usb3phy_reset_l, + .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v4_usb3phy_regs_layout, + .pcs_usb_offset = 0x300, +}; + +static const struct qmp_phy_cfg sm8350_usb3phy_cfg = { + .lanes = 2, + + .serdes_tbl = sm8150_usb3_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl), + .tx_tbl = sm8350_usb3_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(sm8350_usb3_tx_tbl), + .rx_tbl = sm8350_usb3_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(sm8350_usb3_rx_tbl), + .pcs_tbl = sm8350_usb3_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(sm8350_usb3_pcs_tbl), + .pcs_usb_tbl = sm8350_usb3_pcs_usb_tbl, + .pcs_usb_tbl_num = ARRAY_SIZE(sm8350_usb3_pcs_usb_tbl), + .clk_list = qmp_v4_sm8250_usbphy_clk_l, + .num_clks = ARRAY_SIZE(qmp_v4_sm8250_usbphy_clk_l), + .reset_list = msm8996_usb3phy_reset_l, + .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v5_usb3phy_regs_layout, + .pcs_usb_offset = 0x300, +}; + +static void qmp_usb_legacy_configure_lane(void __iomem *base, + const struct qmp_phy_init_tbl tbl[], + int num, + u8 lane_mask) +{ + int i; + const struct qmp_phy_init_tbl *t = tbl; + + if (!t) + return; + + for (i = 0; i < num; i++, t++) { + if (!(t->lane_mask & lane_mask)) + continue; + + writel(t->val, base + t->offset); + } +} + +static void qmp_usb_legacy_configure(void __iomem *base, + const struct qmp_phy_init_tbl tbl[], + int num) +{ + qmp_usb_legacy_configure_lane(base, tbl, num, 0xff); +} + +static int qmp_usb_legacy_serdes_init(struct qmp_usb *qmp) +{ + const struct qmp_phy_cfg *cfg = qmp->cfg; + void __iomem *serdes = qmp->serdes; + const struct qmp_phy_init_tbl *serdes_tbl = cfg->serdes_tbl; + int serdes_tbl_num = cfg->serdes_tbl_num; + + qmp_usb_legacy_configure(serdes, serdes_tbl, serdes_tbl_num); + + return 0; +} + +static void qmp_usb_legacy_init_dp_com(struct phy *phy) +{ + struct qmp_usb *qmp = phy_get_drvdata(phy); + void __iomem *dp_com = qmp->dp_com; + + qphy_setbits(dp_com, QPHY_V3_DP_COM_POWER_DOWN_CTRL, + SW_PWRDN); + /* override hardware control for reset of qmp phy */ + qphy_setbits(dp_com, QPHY_V3_DP_COM_RESET_OVRD_CTRL, + SW_DPPHY_RESET_MUX | SW_DPPHY_RESET | + SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET); + + /* Default type-c orientation, i.e CC1 */ + qphy_setbits(dp_com, QPHY_V3_DP_COM_TYPEC_CTRL, 0x02); + + qphy_setbits(dp_com, QPHY_V3_DP_COM_PHY_MODE_CTRL, + USB3_MODE | DP_MODE); + + /* bring both QMP USB and QMP DP PHYs PCS block out of reset */ + qphy_clrbits(dp_com, QPHY_V3_DP_COM_RESET_OVRD_CTRL, + SW_DPPHY_RESET_MUX | SW_DPPHY_RESET | + SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET); + + qphy_clrbits(dp_com, QPHY_V3_DP_COM_SWI_CTRL, 0x03); + qphy_clrbits(dp_com, QPHY_V3_DP_COM_SW_RESET, SW_RESET); +} + +static int qmp_usb_legacy_init(struct phy *phy) +{ + struct qmp_usb *qmp = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qmp->cfg; + void __iomem *pcs = qmp->pcs; + int ret; + + ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs); + if (ret) { + dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret); + return ret; + } + + ret = reset_control_bulk_assert(cfg->num_resets, qmp->resets); + if (ret) { + dev_err(qmp->dev, "reset assert failed\n"); + goto err_disable_regulators; + } + + ret = reset_control_bulk_deassert(cfg->num_resets, qmp->resets); + if (ret) { + dev_err(qmp->dev, "reset deassert failed\n"); + goto err_disable_regulators; + } + + ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks); + if (ret) + goto err_assert_reset; + + qmp_usb_legacy_init_dp_com(phy); + + qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN); + + return 0; + +err_assert_reset: + reset_control_bulk_assert(cfg->num_resets, qmp->resets); +err_disable_regulators: + regulator_bulk_disable(cfg->num_vregs, qmp->vregs); + + return ret; +} + +static int qmp_usb_legacy_exit(struct phy *phy) +{ + struct qmp_usb *qmp = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qmp->cfg; + + reset_control_bulk_assert(cfg->num_resets, qmp->resets); + + clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks); + + regulator_bulk_disable(cfg->num_vregs, qmp->vregs); + + return 0; +} + +static int qmp_usb_legacy_power_on(struct phy *phy) +{ + struct qmp_usb *qmp = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qmp->cfg; + void __iomem *tx = qmp->tx; + void __iomem *rx = qmp->rx; + void __iomem *pcs = qmp->pcs; + void __iomem *status; + unsigned int val; + int ret; + + qmp_usb_legacy_serdes_init(qmp); + + ret = clk_prepare_enable(qmp->pipe_clk); + if (ret) { + dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret); + return ret; + } + + /* Tx, Rx, and PCS configurations */ + qmp_usb_legacy_configure_lane(tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); + qmp_usb_legacy_configure_lane(rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); + + if (cfg->lanes >= 2) { + qmp_usb_legacy_configure_lane(qmp->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2); + qmp_usb_legacy_configure_lane(qmp->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2); + } + + qmp_usb_legacy_configure(pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); + + usleep_range(10, 20); + + /* Pull PHY out of reset state */ + qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); + + /* start SerDes and Phy-Coding-Sublayer */ + qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], SERDES_START | PCS_START); + + status = pcs + cfg->regs[QPHY_PCS_STATUS]; + ret = readl_poll_timeout(status, val, !(val & PHYSTATUS), 200, + PHY_INIT_COMPLETE_TIMEOUT); + if (ret) { + dev_err(qmp->dev, "phy initialization timed-out\n"); + goto err_disable_pipe_clk; + } + + return 0; + +err_disable_pipe_clk: + clk_disable_unprepare(qmp->pipe_clk); + + return ret; +} + +static int qmp_usb_legacy_power_off(struct phy *phy) +{ + struct qmp_usb *qmp = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qmp->cfg; + + clk_disable_unprepare(qmp->pipe_clk); + + /* PHY reset */ + qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); + + /* stop SerDes and Phy-Coding-Sublayer */ + qphy_clrbits(qmp->pcs, cfg->regs[QPHY_START_CTRL], + SERDES_START | PCS_START); + + /* Put PHY into POWER DOWN state: active low */ + qphy_clrbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], + SW_PWRDN); + + return 0; +} + +static int qmp_usb_legacy_enable(struct phy *phy) +{ + int ret; + + ret = qmp_usb_legacy_init(phy); + if (ret) + return ret; + + ret = qmp_usb_legacy_power_on(phy); + if (ret) + qmp_usb_legacy_exit(phy); + + return ret; +} + +static int qmp_usb_legacy_disable(struct phy *phy) +{ + int ret; + + ret = qmp_usb_legacy_power_off(phy); + if (ret) + return ret; + return qmp_usb_legacy_exit(phy); +} + +static int qmp_usb_legacy_set_mode(struct phy *phy, enum phy_mode mode, int submode) +{ + struct qmp_usb *qmp = phy_get_drvdata(phy); + + qmp->mode = mode; + + return 0; +} + +static const struct phy_ops qmp_usb_legacy_phy_ops = { + .init = qmp_usb_legacy_enable, + .exit = qmp_usb_legacy_disable, + .set_mode = qmp_usb_legacy_set_mode, + .owner = THIS_MODULE, +}; + +static void qmp_usb_legacy_enable_autonomous_mode(struct qmp_usb *qmp) +{ + const struct qmp_phy_cfg *cfg = qmp->cfg; + void __iomem *pcs_usb = qmp->pcs_usb ?: qmp->pcs; + void __iomem *pcs_misc = qmp->pcs_misc; + u32 intr_mask; + + if (qmp->mode == PHY_MODE_USB_HOST_SS || + qmp->mode == PHY_MODE_USB_DEVICE_SS) + intr_mask = ARCVR_DTCT_EN | ALFPS_DTCT_EN; + else + intr_mask = ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL; + + /* Clear any pending interrupts status */ + qphy_setbits(pcs_usb, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); + /* Writing 1 followed by 0 clears the interrupt */ + qphy_clrbits(pcs_usb, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); + + qphy_clrbits(pcs_usb, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], + ARCVR_DTCT_EN | ALFPS_DTCT_EN | ARCVR_DTCT_EVENT_SEL); + + /* Enable required PHY autonomous mode interrupts */ + qphy_setbits(pcs_usb, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], intr_mask); + + /* Enable i/o clamp_n for autonomous mode */ + if (pcs_misc) + qphy_clrbits(pcs_misc, QPHY_V3_PCS_MISC_CLAMP_ENABLE, CLAMP_EN); +} + +static void qmp_usb_legacy_disable_autonomous_mode(struct qmp_usb *qmp) +{ + const struct qmp_phy_cfg *cfg = qmp->cfg; + void __iomem *pcs_usb = qmp->pcs_usb ?: qmp->pcs; + void __iomem *pcs_misc = qmp->pcs_misc; + + /* Disable i/o clamp_n on resume for normal mode */ + if (pcs_misc) + qphy_setbits(pcs_misc, QPHY_V3_PCS_MISC_CLAMP_ENABLE, CLAMP_EN); + + qphy_clrbits(pcs_usb, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], + ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL | ALFPS_DTCT_EN); + + qphy_setbits(pcs_usb, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); + /* Writing 1 followed by 0 clears the interrupt */ + qphy_clrbits(pcs_usb, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); +} + +static int __maybe_unused qmp_usb_legacy_runtime_suspend(struct device *dev) +{ + struct qmp_usb *qmp = dev_get_drvdata(dev); + const struct qmp_phy_cfg *cfg = qmp->cfg; + + dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode); + + if (!qmp->phy->init_count) { + dev_vdbg(dev, "PHY not initialized, bailing out\n"); + return 0; + } + + qmp_usb_legacy_enable_autonomous_mode(qmp); + + clk_disable_unprepare(qmp->pipe_clk); + clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks); + + return 0; +} + +static int __maybe_unused qmp_usb_legacy_runtime_resume(struct device *dev) +{ + struct qmp_usb *qmp = dev_get_drvdata(dev); + const struct qmp_phy_cfg *cfg = qmp->cfg; + int ret = 0; + + dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode); + + if (!qmp->phy->init_count) { + dev_vdbg(dev, "PHY not initialized, bailing out\n"); + return 0; + } + + ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks); + if (ret) + return ret; + + ret = clk_prepare_enable(qmp->pipe_clk); + if (ret) { + dev_err(dev, "pipe_clk enable failed, err=%d\n", ret); + clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks); + return ret; + } + + qmp_usb_legacy_disable_autonomous_mode(qmp); + + return 0; +} + +static const struct dev_pm_ops qmp_usb_legacy_pm_ops = { + SET_RUNTIME_PM_OPS(qmp_usb_legacy_runtime_suspend, + qmp_usb_legacy_runtime_resume, NULL) +}; + +static int qmp_usb_legacy_vreg_init(struct qmp_usb *qmp) +{ + const struct qmp_phy_cfg *cfg = qmp->cfg; + struct device *dev = qmp->dev; + int num = cfg->num_vregs; + int i; + + qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL); + if (!qmp->vregs) + return -ENOMEM; + + for (i = 0; i < num; i++) + qmp->vregs[i].supply = cfg->vreg_list[i]; + + return devm_regulator_bulk_get(dev, num, qmp->vregs); +} + +static int qmp_usb_legacy_reset_init(struct qmp_usb *qmp) +{ + const struct qmp_phy_cfg *cfg = qmp->cfg; + struct device *dev = qmp->dev; + int i; + int ret; + + qmp->resets = devm_kcalloc(dev, cfg->num_resets, + sizeof(*qmp->resets), GFP_KERNEL); + if (!qmp->resets) + return -ENOMEM; + + for (i = 0; i < cfg->num_resets; i++) + qmp->resets[i].id = cfg->reset_list[i]; + + ret = devm_reset_control_bulk_get_exclusive(dev, cfg->num_resets, qmp->resets); + if (ret) + return dev_err_probe(dev, ret, "failed to get resets\n"); + + return 0; +} + +static int qmp_usb_legacy_clk_init(struct qmp_usb *qmp) +{ + const struct qmp_phy_cfg *cfg = qmp->cfg; + struct device *dev = qmp->dev; + int num = cfg->num_clks; + int i; + + qmp->clks = devm_kcalloc(dev, num, sizeof(*qmp->clks), GFP_KERNEL); + if (!qmp->clks) + return -ENOMEM; + + for (i = 0; i < num; i++) + qmp->clks[i].id = cfg->clk_list[i]; + + return devm_clk_bulk_get(dev, num, qmp->clks); +} + +static void phy_clk_release_provider(void *res) +{ + of_clk_del_provider(res); +} + +/* + * Register a fixed rate pipe clock. + * + * The _pipe_clksrc generated by PHY goes to the GCC that gate + * controls it. The _pipe_clk coming out of the GCC is requested + * by the PHY driver for its operations. + * We register the _pipe_clksrc here. The gcc driver takes care + * of assigning this _pipe_clksrc as parent to _pipe_clk. + * Below picture shows this relationship. + * + * +---------------+ + * | PHY block |<<---------------------------------------+ + * | | | + * | +-------+ | +-----+ | + * I/P---^-->| PLL |---^--->pipe_clksrc--->| GCC |--->pipe_clk---+ + * clk | +-------+ | +-----+ + * +---------------+ + */ +static int phy_pipe_clk_register(struct qmp_usb *qmp, struct device_node *np) +{ + struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed; + struct clk_init_data init = { }; + int ret; + + ret = of_property_read_string(np, "clock-output-names", &init.name); + if (ret) { + dev_err(qmp->dev, "%pOFn: No clock-output-names\n", np); + return ret; + } + + init.ops = &clk_fixed_rate_ops; + + /* controllers using QMP phys use 125MHz pipe clock interface */ + fixed->fixed_rate = 125000000; + fixed->hw.init = &init; + + ret = devm_clk_hw_register(qmp->dev, &fixed->hw); + if (ret) + return ret; + + ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &fixed->hw); + if (ret) + return ret; + + /* + * Roll a devm action because the clock provider is the child node, but + * the child node is not actually a device. + */ + return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, np); +} + +static void __iomem *qmp_usb_legacy_iomap(struct device *dev, struct device_node *np, + int index, bool exclusive) +{ + struct resource res; + + if (!exclusive) { + if (of_address_to_resource(np, index, &res)) + return IOMEM_ERR_PTR(-EINVAL); + + return devm_ioremap(dev, res.start, resource_size(&res)); + } + + return devm_of_iomap(dev, np, index, NULL); +} + +static int qmp_usb_legacy_parse_dt_legacy(struct qmp_usb *qmp, struct device_node *np) +{ + struct platform_device *pdev = to_platform_device(qmp->dev); + const struct qmp_phy_cfg *cfg = qmp->cfg; + struct device *dev = qmp->dev; + bool exclusive = true; + + qmp->serdes = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(qmp->serdes)) + return PTR_ERR(qmp->serdes); + + qmp->dp_com = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(qmp->dp_com)) + return PTR_ERR(qmp->dp_com); + + /* + * Get memory resources for the PHY: + * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2. + * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5 + * For single lane PHYs: pcs_misc (optional) -> 3. + */ + qmp->tx = devm_of_iomap(dev, np, 0, NULL); + if (IS_ERR(qmp->tx)) + return PTR_ERR(qmp->tx); + + qmp->rx = devm_of_iomap(dev, np, 1, NULL); + if (IS_ERR(qmp->rx)) + return PTR_ERR(qmp->rx); + + qmp->pcs = qmp_usb_legacy_iomap(dev, np, 2, exclusive); + if (IS_ERR(qmp->pcs)) + return PTR_ERR(qmp->pcs); + + if (cfg->pcs_usb_offset) + qmp->pcs_usb = qmp->pcs + cfg->pcs_usb_offset; + + if (cfg->lanes >= 2) { + qmp->tx2 = devm_of_iomap(dev, np, 3, NULL); + if (IS_ERR(qmp->tx2)) + return PTR_ERR(qmp->tx2); + + qmp->rx2 = devm_of_iomap(dev, np, 4, NULL); + if (IS_ERR(qmp->rx2)) + return PTR_ERR(qmp->rx2); + + qmp->pcs_misc = devm_of_iomap(dev, np, 5, NULL); + } else { + qmp->pcs_misc = devm_of_iomap(dev, np, 3, NULL); + } + + if (IS_ERR(qmp->pcs_misc)) { + dev_vdbg(dev, "PHY pcs_misc-reg not used\n"); + qmp->pcs_misc = NULL; + } + + qmp->pipe_clk = devm_get_clk_from_child(dev, np, NULL); + if (IS_ERR(qmp->pipe_clk)) { + return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk), + "failed to get pipe clock\n"); + } + + return 0; +} + +static int qmp_usb_legacy_parse_dt(struct qmp_usb *qmp) +{ + struct platform_device *pdev = to_platform_device(qmp->dev); + const struct qmp_phy_cfg *cfg = qmp->cfg; + const struct qmp_usb_legacy_offsets *offs = cfg->offsets; + struct device *dev = qmp->dev; + void __iomem *base; + + if (!offs) + return -EINVAL; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + qmp->serdes = base + offs->serdes; + qmp->pcs = base + offs->pcs; + qmp->pcs_usb = base + offs->pcs_usb; + qmp->tx = base + offs->tx; + qmp->rx = base + offs->rx; + + qmp->pipe_clk = devm_clk_get(dev, "pipe"); + if (IS_ERR(qmp->pipe_clk)) { + return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk), + "failed to get pipe clock\n"); + } + + return 0; +} + +static int qmp_usb_legacy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy_provider *phy_provider; + struct device_node *np; + struct qmp_usb *qmp; + int ret; + + qmp = devm_kzalloc(dev, sizeof(*qmp), GFP_KERNEL); + if (!qmp) + return -ENOMEM; + + qmp->dev = dev; + + qmp->cfg = of_device_get_match_data(dev); + if (!qmp->cfg) + return -EINVAL; + + ret = qmp_usb_legacy_clk_init(qmp); + if (ret) + return ret; + + ret = qmp_usb_legacy_reset_init(qmp); + if (ret) + return ret; + + ret = qmp_usb_legacy_vreg_init(qmp); + if (ret) + return ret; + + /* Check for legacy binding with child node. */ + np = of_get_next_available_child(dev->of_node, NULL); + if (np) { + ret = qmp_usb_legacy_parse_dt_legacy(qmp, np); + } else { + np = of_node_get(dev->of_node); + ret = qmp_usb_legacy_parse_dt(qmp); + } + if (ret) + goto err_node_put; + + pm_runtime_set_active(dev); + ret = devm_pm_runtime_enable(dev); + if (ret) + goto err_node_put; + /* + * Prevent runtime pm from being ON by default. Users can enable + * it using power/control in sysfs. + */ + pm_runtime_forbid(dev); + + ret = phy_pipe_clk_register(qmp, np); + if (ret) + goto err_node_put; + + qmp->phy = devm_phy_create(dev, np, &qmp_usb_legacy_phy_ops); + if (IS_ERR(qmp->phy)) { + ret = PTR_ERR(qmp->phy); + dev_err(dev, "failed to create PHY: %d\n", ret); + goto err_node_put; + } + + phy_set_drvdata(qmp->phy, qmp); + + of_node_put(np); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); + +err_node_put: + of_node_put(np); + return ret; +} + +static const struct of_device_id qmp_usb_legacy_of_match_table[] = { + { + .compatible = "qcom,sc7180-qmp-usb3-phy", + .data = &sc7180_usb3phy_cfg, + }, { + .compatible = "qcom,sc8180x-qmp-usb3-phy", + .data = &sm8150_usb3phy_cfg, + }, { + .compatible = "qcom,sdm845-qmp-usb3-phy", + .data = &qmp_v3_usb3phy_cfg, + }, { + .compatible = "qcom,sm8150-qmp-usb3-phy", + .data = &sm8150_usb3phy_cfg, + }, { + .compatible = "qcom,sm8250-qmp-usb3-phy", + .data = &sm8250_usb3phy_cfg, + }, { + .compatible = "qcom,sm8350-qmp-usb3-phy", + .data = &sm8350_usb3phy_cfg, + }, { + .compatible = "qcom,sm8450-qmp-usb3-phy", + .data = &sm8350_usb3phy_cfg, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, qmp_usb_legacy_of_match_table); + +static struct platform_driver qmp_usb_legacy_driver = { + .probe = qmp_usb_legacy_probe, + .driver = { + .name = "qcom-qmp-usb-legacy-phy", + .pm = &qmp_usb_legacy_pm_ops, + .of_match_table = qmp_usb_legacy_of_match_table, + }, +}; + +module_platform_driver(qmp_usb_legacy_driver); + +MODULE_AUTHOR("Vivek Gautam "); +MODULE_DESCRIPTION("Qualcomm QMP legacy USB+DP PHY driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c index 466f0a56c82e1..f8c598dbf4674 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c @@ -367,112 +367,6 @@ static const struct qmp_phy_init_tbl msm8996_usb3_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V2_PCS_POWER_STATE_CONFIG2, 0x08), }; -static const struct qmp_phy_init_tbl qmp_v3_usb3_serdes_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x08), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL2, 0x08), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x16), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x01), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x80), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START1_MODE0, 0xab), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START2_MODE0, 0xea), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START3_MODE0, 0x02), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xc9), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORECLK_DIV_MODE0, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP3_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x34), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0x15), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x04), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_CFG, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_BUF_ENABLE, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_EN_CENTER, 0x01), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER1, 0x31), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER2, 0x01), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER2, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE1, 0x85), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE2, 0x07), -}; - -static const struct qmp_phy_init_tbl qmp_v3_usb3_tx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10), - QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12), - QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x16), - QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x09), - QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x06), -}; - -static const struct qmp_phy_init_tbl qmp_v3_usb3_rx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x03), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x16), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75), -}; - -static const struct qmp_phy_init_tbl qmp_v3_usb3_pcs_tbl[] = { - /* FLL settings */ - QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x40), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02), - - /* Lock Det settings */ - QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG1, 0xd1), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG2, 0x1f), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG3, 0x47), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_POWER_STATE_CONFIG2, 0x1b), - - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0xba), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V1, 0x9f), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V2, 0xb7), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V3, 0x4e), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V4, 0x65), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_LS, 0x6b), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x15), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0d), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V1, 0x15), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V1, 0x0d), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V2, 0x15), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V2, 0x0d), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V3, 0x15), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V3, 0x1d), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V4, 0x15), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V4, 0x0d), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_LS, 0x15), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_LS, 0x0d), - - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RATE_SLEW_CNTRL, 0x02), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TSYNC_RSYNC_TIME, 0x44), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L, 0x40), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H, 0x00), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME, 0x75), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13), -}; - static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07), QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14), @@ -693,117 +587,6 @@ static const struct qmp_phy_init_tbl msm8998_usb3_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13), }; -static const struct qmp_phy_init_tbl sm8150_usb3_serdes_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_EN_CENTER, 0x01), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_PER1, 0x31), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_PER2, 0x01), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE1_MODE0, 0xde), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE2_MODE0, 0x07), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE1_MODE1, 0xde), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE2_MODE1, 0x07), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_BUF_ENABLE, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_IPTRIM, 0x20), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE0, 0x06), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE1, 0x06), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE0, 0x16), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE1, 0x16), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE0, 0x36), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE1, 0x36), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x1a), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x04), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x14), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x34), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE1, 0x34), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE1, 0x82), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0x82), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE1, 0x82), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START1_MODE0, 0xab), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE0, 0xea), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x02), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_MAP, 0x02), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START1_MODE1, 0xab), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE1, 0xea), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE1, 0x02), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE1_MODE0, 0x24), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE1_MODE1, 0x24), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE2_MODE1, 0x02), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x01), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORECLK_DIV_MODE1, 0x08), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xca), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1e), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xca), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x1e), - QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_HSCLK_SEL, 0x11), -}; - -static const struct qmp_phy_init_tbl sm8150_usb3_tx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_TX, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_RX, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V4_TX_LANE_MODE_1, 0xd5), - QMP_PHY_INIT_CFG(QSERDES_V4_TX_RCV_DETECT_LVL_2, 0x12), - QMP_PHY_INIT_CFG(QSERDES_V4_TX_PI_QEC_CTRL, 0x20), -}; - -static const struct qmp_phy_init_tbl sm8150_usb3_rx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_GAIN, 0x05), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_FO_GAIN, 0x2f), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7f), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_COUNT_LOW, 0xff), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_PI_CONTROLS, 0x99), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_THRESH1, 0x04), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_THRESH2, 0x08), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_GAIN1, 0x05), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_GAIN2, 0x05), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_VGA_CAL_CNTRL1, 0x54), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_VGA_CAL_CNTRL2, 0x0e), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4a), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_LOW, 0xc0), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_HIGH, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_CNTRL, 0x04), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_DEGLITCH_CNTRL, 0x0e), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_LOW, 0xbf), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH, 0xbf), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH2, 0x3f), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH3, 0x7f), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH4, 0x94), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_LOW, 0xdc), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH, 0xdc), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH2, 0x5c), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH3, 0x0b), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH4, 0xb3), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_DFE_EN_TIMER, 0x04), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_AUX_DATA_TCOARSE_TFINE, 0xa0), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_DCC_CTRL1, 0x0c), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_GM_CAL, 0x1f), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_VTH_CODE, 0x10), -}; - -static const struct qmp_phy_init_tbl sm8150_usb3_pcs_tbl[] = { - /* Lock Det settings */ - QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG1, 0xd0), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG2, 0x07), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG6, 0x13), - - QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x21), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_SIGDET_LVL, 0xaa), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_CDR_RESET_TIME, 0x0a), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG1, 0x88), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG2, 0x13), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCS_TX_RX_CONFIG, 0x0c), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG1, 0x4b), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG5, 0x10), -}; - -static const struct qmp_phy_init_tbl sm8150_usb3_pcs_usb_tbl[] = { - QMP_PHY_INIT_CFG(QPHY_V4_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07), -}; - static const struct qmp_phy_init_tbl sm8150_usb3_uniphy_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x1a), QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_HSCLK_SEL, 0x11), @@ -915,78 +698,6 @@ static const struct qmp_phy_init_tbl sm8150_usb3_uniphy_pcs_usb_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V4_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07), }; -static const struct qmp_phy_init_tbl sm8250_usb3_tx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_TX, 0x60), - QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_RX, 0x60), - QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_OFFSET_TX, 0x11), - QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_OFFSET_RX, 0x02), - QMP_PHY_INIT_CFG(QSERDES_V4_TX_LANE_MODE_1, 0xd5), - QMP_PHY_INIT_CFG(QSERDES_V4_TX_RCV_DETECT_LVL_2, 0x12), - QMP_PHY_INIT_CFG_LANE(QSERDES_V4_TX_PI_QEC_CTRL, 0x40, 1), - QMP_PHY_INIT_CFG_LANE(QSERDES_V4_TX_PI_QEC_CTRL, 0x54, 2), -}; - -static const struct qmp_phy_init_tbl sm8250_usb3_rx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_GAIN, 0x06), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_FO_GAIN, 0x2f), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7f), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_COUNT_LOW, 0xff), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_PI_CONTROLS, 0x99), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_THRESH1, 0x04), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_THRESH2, 0x08), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_GAIN1, 0x05), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_GAIN2, 0x05), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_VGA_CAL_CNTRL1, 0x54), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_VGA_CAL_CNTRL2, 0x0c), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4a), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_LOW, 0xc0), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_HIGH, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_CNTRL, 0x04), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_DEGLITCH_CNTRL, 0x0e), - QMP_PHY_INIT_CFG_LANE(QSERDES_V4_RX_RX_MODE_00_LOW, 0xff, 1), - QMP_PHY_INIT_CFG_LANE(QSERDES_V4_RX_RX_MODE_00_LOW, 0x7f, 2), - QMP_PHY_INIT_CFG_LANE(QSERDES_V4_RX_RX_MODE_00_HIGH, 0x7f, 1), - QMP_PHY_INIT_CFG_LANE(QSERDES_V4_RX_RX_MODE_00_HIGH, 0xff, 2), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH2, 0x7f), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH3, 0x7f), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH4, 0x97), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_LOW, 0xdc), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH, 0xdc), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH2, 0x5c), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH3, 0x7b), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH4, 0xb4), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_DFE_EN_TIMER, 0x04), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_AUX_DATA_TCOARSE_TFINE, 0xa0), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_DCC_CTRL1, 0x0c), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_GM_CAL, 0x1f), - QMP_PHY_INIT_CFG(QSERDES_V4_RX_VTH_CODE, 0x10), -}; - -static const struct qmp_phy_init_tbl sm8250_usb3_pcs_tbl[] = { - QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG1, 0xd0), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG2, 0x07), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG3, 0x20), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG6, 0x13), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x21), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_SIGDET_LVL, 0xa9), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_CDR_RESET_TIME, 0x0a), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG1, 0x88), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG2, 0x13), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCS_TX_RX_CONFIG, 0x0c), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG1, 0x4b), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG5, 0x10), -}; - -static const struct qmp_phy_init_tbl sm8250_usb3_pcs_usb_tbl[] = { - QMP_PHY_INIT_CFG(QPHY_V4_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07), -}; - static const struct qmp_phy_init_tbl sm8250_usb3_uniphy_tx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V4_TX_RCV_DETECT_LVL_2, 0x12), QMP_PHY_INIT_CFG(QSERDES_V4_TX_LANE_MODE_1, 0xd5), @@ -1148,84 +859,6 @@ static const struct qmp_phy_init_tbl sdx65_usb3_uniphy_rx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_ENABLES, 0x00), }; -static const struct qmp_phy_init_tbl sm8350_usb3_tx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_TX, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_RX, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_TX, 0x16), - QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, 0x0e), - QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_1, 0x35), - QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_3, 0x3f), - QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_4, 0x7f), - QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_5, 0x3f), - QMP_PHY_INIT_CFG(QSERDES_V5_TX_RCV_DETECT_LVL_2, 0x12), - QMP_PHY_INIT_CFG(QSERDES_V5_TX_PI_QEC_CTRL, 0x21), -}; - -static const struct qmp_phy_init_tbl sm8350_usb3_rx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FO_GAIN, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SO_GAIN, 0x05), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_FO_GAIN, 0x2f), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7f), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_LOW, 0xff), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_PI_CONTROLS, 0x99), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_THRESH1, 0x08), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_THRESH2, 0x08), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_GAIN1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_GAIN2, 0x04), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL1, 0x54), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL2, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4a), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_IDAC_TSETTLE_LOW, 0xc0), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_IDAC_TSETTLE_HIGH, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x47), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_CNTRL, 0x04), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_DEGLITCH_CNTRL, 0x0e), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_LOW, 0xbb), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH, 0x7b), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH2, 0xbb), - QMP_PHY_INIT_CFG_LANE(QSERDES_V5_RX_RX_MODE_00_HIGH3, 0x3d, 1), - QMP_PHY_INIT_CFG_LANE(QSERDES_V5_RX_RX_MODE_00_HIGH3, 0x3c, 2), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH4, 0xdb), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_LOW, 0x64), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH, 0x24), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH2, 0xd2), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH3, 0x13), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH4, 0xa9), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_DFE_EN_TIMER, 0x04), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_AUX_DATA_TCOARSE_TFINE, 0xa0), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_DCC_CTRL1, 0x0c), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_GM_CAL, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_VTH_CODE, 0x10), -}; - -static const struct qmp_phy_init_tbl sm8350_usb3_pcs_tbl[] = { - QMP_PHY_INIT_CFG(QPHY_V4_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG1, 0xd0), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG2, 0x07), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG3, 0x20), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG6, 0x13), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x21), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_SIGDET_LVL, 0xaa), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_CDR_RESET_TIME, 0x0a), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG1, 0x88), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG2, 0x13), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCS_TX_RX_CONFIG, 0x0c), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG1, 0x4b), - QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG5, 0x10), -}; - -static const struct qmp_phy_init_tbl sm8350_usb3_pcs_usb_tbl[] = { - QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_RCVR_DTCT_DLY_U3_L, 0x40), - QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_RCVR_DTCT_DLY_U3_H, 0x00), - QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8), - QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07), -}; - static const struct qmp_phy_init_tbl sm8350_usb3_uniphy_tx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_1, 0xa5), QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_2, 0x82), @@ -1556,9 +1189,6 @@ struct qmp_phy_cfg { /* true, if PHY needs delay after POWER_DOWN */ bool has_pwrdn_delay; - /* true, if PHY has a separate DP_COM control block */ - bool has_phy_dp_com_ctrl; - /* Offset from PCS to PCS_USB region */ unsigned int pcs_usb_offset; }; @@ -1577,8 +1207,6 @@ struct qmp_usb { void __iomem *tx2; void __iomem *rx2; - void __iomem *dp_com; - struct clk *pipe_clk; struct clk_bulk_data *clks; struct reset_control_bulk_data *resets; @@ -1632,11 +1260,6 @@ static const char * const qmp_v4_ref_phy_clk_l[] = { "aux", "ref_clk_src", "ref", "com_aux", }; -/* the primary usb3 phy on sm8250 doesn't have a ref clock */ -static const char * const qmp_v4_sm8250_usbphy_clk_l[] = { - "aux", "ref_clk_src", "com_aux" -}; - /* usb3 phy on sdx55 doesn't have com_aux clock */ static const char * const qmp_v4_sdx55_usbphy_clk_l[] = { "aux", "cfg_ahb", "ref" @@ -1651,10 +1274,6 @@ static const char * const msm8996_usb3phy_reset_l[] = { "phy", "common", }; -static const char * const sc7180_usb3phy_reset_l[] = { - "phy", -}; - static const char * const qcm2290_usb3phy_reset_l[] = { "phy_phy", "phy", }; @@ -1752,29 +1371,6 @@ static const struct qmp_phy_cfg msm8996_usb3phy_cfg = { .regs = qmp_v2_usb3phy_regs_layout, }; -static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = { - .lanes = 2, - - .serdes_tbl = qmp_v3_usb3_serdes_tbl, - .serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl), - .tx_tbl = qmp_v3_usb3_tx_tbl, - .tx_tbl_num = ARRAY_SIZE(qmp_v3_usb3_tx_tbl), - .rx_tbl = qmp_v3_usb3_rx_tbl, - .rx_tbl_num = ARRAY_SIZE(qmp_v3_usb3_rx_tbl), - .pcs_tbl = qmp_v3_usb3_pcs_tbl, - .pcs_tbl_num = ARRAY_SIZE(qmp_v3_usb3_pcs_tbl), - .clk_list = qmp_v3_phy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l), - .reset_list = msm8996_usb3phy_reset_l, - .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), - .regs = qmp_v3_usb3phy_regs_layout, - - .has_pwrdn_delay = true, - .has_phy_dp_com_ctrl = true, -}; - static const struct qmp_phy_cfg sa8775p_usb3_uniphy_cfg = { .lanes = 1, @@ -1797,29 +1393,6 @@ static const struct qmp_phy_cfg sa8775p_usb3_uniphy_cfg = { .regs = qmp_v5_usb3phy_regs_layout, }; -static const struct qmp_phy_cfg sc7180_usb3phy_cfg = { - .lanes = 2, - - .serdes_tbl = qmp_v3_usb3_serdes_tbl, - .serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl), - .tx_tbl = qmp_v3_usb3_tx_tbl, - .tx_tbl_num = ARRAY_SIZE(qmp_v3_usb3_tx_tbl), - .rx_tbl = qmp_v3_usb3_rx_tbl, - .rx_tbl_num = ARRAY_SIZE(qmp_v3_usb3_rx_tbl), - .pcs_tbl = qmp_v3_usb3_pcs_tbl, - .pcs_tbl_num = ARRAY_SIZE(qmp_v3_usb3_pcs_tbl), - .clk_list = qmp_v3_phy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l), - .reset_list = sc7180_usb3phy_reset_l, - .num_resets = ARRAY_SIZE(sc7180_usb3phy_reset_l), - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), - .regs = qmp_v3_usb3phy_regs_layout, - - .has_pwrdn_delay = true, - .has_phy_dp_com_ctrl = true, -}; - static const struct qmp_phy_cfg sc8280xp_usb3_uniphy_cfg = { .lanes = 1, @@ -1884,32 +1457,6 @@ static const struct qmp_phy_cfg msm8998_usb3phy_cfg = { .regs = qmp_v3_usb3phy_regs_layout, }; -static const struct qmp_phy_cfg sm8150_usb3phy_cfg = { - .lanes = 2, - - .serdes_tbl = sm8150_usb3_serdes_tbl, - .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl), - .tx_tbl = sm8150_usb3_tx_tbl, - .tx_tbl_num = ARRAY_SIZE(sm8150_usb3_tx_tbl), - .rx_tbl = sm8150_usb3_rx_tbl, - .rx_tbl_num = ARRAY_SIZE(sm8150_usb3_rx_tbl), - .pcs_tbl = sm8150_usb3_pcs_tbl, - .pcs_tbl_num = ARRAY_SIZE(sm8150_usb3_pcs_tbl), - .pcs_usb_tbl = sm8150_usb3_pcs_usb_tbl, - .pcs_usb_tbl_num = ARRAY_SIZE(sm8150_usb3_pcs_usb_tbl), - .clk_list = qmp_v4_ref_phy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v4_ref_phy_clk_l), - .reset_list = msm8996_usb3phy_reset_l, - .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), - .regs = qmp_v4_usb3phy_regs_layout, - .pcs_usb_offset = 0x300, - - .has_pwrdn_delay = true, - .has_phy_dp_com_ctrl = true, -}; - static const struct qmp_phy_cfg sm8150_usb3_uniphy_cfg = { .lanes = 1, @@ -1935,32 +1482,6 @@ static const struct qmp_phy_cfg sm8150_usb3_uniphy_cfg = { .has_pwrdn_delay = true, }; -static const struct qmp_phy_cfg sm8250_usb3phy_cfg = { - .lanes = 2, - - .serdes_tbl = sm8150_usb3_serdes_tbl, - .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl), - .tx_tbl = sm8250_usb3_tx_tbl, - .tx_tbl_num = ARRAY_SIZE(sm8250_usb3_tx_tbl), - .rx_tbl = sm8250_usb3_rx_tbl, - .rx_tbl_num = ARRAY_SIZE(sm8250_usb3_rx_tbl), - .pcs_tbl = sm8250_usb3_pcs_tbl, - .pcs_tbl_num = ARRAY_SIZE(sm8250_usb3_pcs_tbl), - .pcs_usb_tbl = sm8250_usb3_pcs_usb_tbl, - .pcs_usb_tbl_num = ARRAY_SIZE(sm8250_usb3_pcs_usb_tbl), - .clk_list = qmp_v4_sm8250_usbphy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v4_sm8250_usbphy_clk_l), - .reset_list = msm8996_usb3phy_reset_l, - .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), - .regs = qmp_v4_usb3phy_regs_layout, - .pcs_usb_offset = 0x300, - - .has_pwrdn_delay = true, - .has_phy_dp_com_ctrl = true, -}; - static const struct qmp_phy_cfg sm8250_usb3_uniphy_cfg = { .lanes = 1, @@ -2036,32 +1557,6 @@ static const struct qmp_phy_cfg sdx65_usb3_uniphy_cfg = { .has_pwrdn_delay = true, }; -static const struct qmp_phy_cfg sm8350_usb3phy_cfg = { - .lanes = 2, - - .serdes_tbl = sm8150_usb3_serdes_tbl, - .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl), - .tx_tbl = sm8350_usb3_tx_tbl, - .tx_tbl_num = ARRAY_SIZE(sm8350_usb3_tx_tbl), - .rx_tbl = sm8350_usb3_rx_tbl, - .rx_tbl_num = ARRAY_SIZE(sm8350_usb3_rx_tbl), - .pcs_tbl = sm8350_usb3_pcs_tbl, - .pcs_tbl_num = ARRAY_SIZE(sm8350_usb3_pcs_tbl), - .pcs_usb_tbl = sm8350_usb3_pcs_usb_tbl, - .pcs_usb_tbl_num = ARRAY_SIZE(sm8350_usb3_pcs_usb_tbl), - .clk_list = qmp_v4_sm8250_usbphy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v4_sm8250_usbphy_clk_l), - .reset_list = msm8996_usb3phy_reset_l, - .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), - .regs = qmp_v5_usb3phy_regs_layout, - .pcs_usb_offset = 0x300, - - .has_pwrdn_delay = true, - .has_phy_dp_com_ctrl = true, -}; - static const struct qmp_phy_cfg sm8350_usb3_uniphy_cfg = { .lanes = 1, @@ -2152,7 +1647,6 @@ static int qmp_usb_init(struct phy *phy) struct qmp_usb *qmp = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qmp->cfg; void __iomem *pcs = qmp->pcs; - void __iomem *dp_com = qmp->dp_com; int ret; ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs); @@ -2177,29 +1671,6 @@ static int qmp_usb_init(struct phy *phy) if (ret) goto err_assert_reset; - if (cfg->has_phy_dp_com_ctrl) { - qphy_setbits(dp_com, QPHY_V3_DP_COM_POWER_DOWN_CTRL, - SW_PWRDN); - /* override hardware control for reset of qmp phy */ - qphy_setbits(dp_com, QPHY_V3_DP_COM_RESET_OVRD_CTRL, - SW_DPPHY_RESET_MUX | SW_DPPHY_RESET | - SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET); - - /* Default type-c orientation, i.e CC1 */ - qphy_setbits(dp_com, QPHY_V3_DP_COM_TYPEC_CTRL, 0x02); - - qphy_setbits(dp_com, QPHY_V3_DP_COM_PHY_MODE_CTRL, - USB3_MODE | DP_MODE); - - /* bring both QMP USB and QMP DP PHYs PCS block out of reset */ - qphy_clrbits(dp_com, QPHY_V3_DP_COM_RESET_OVRD_CTRL, - SW_DPPHY_RESET_MUX | SW_DPPHY_RESET | - SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET); - - qphy_clrbits(dp_com, QPHY_V3_DP_COM_SWI_CTRL, 0x03); - qphy_clrbits(dp_com, QPHY_V3_DP_COM_SW_RESET, SW_RESET); - } - qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN); return 0; @@ -2582,12 +2053,6 @@ static int qmp_usb_parse_dt_legacy(struct qmp_usb *qmp, struct device_node *np) if (IS_ERR(qmp->serdes)) return PTR_ERR(qmp->serdes); - if (cfg->has_phy_dp_com_ctrl) { - qmp->dp_com = devm_platform_ioremap_resource(pdev, 1); - if (IS_ERR(qmp->dp_com)) - return PTR_ERR(qmp->dp_com); - } - /* * FIXME: These bindings should be fixed to not rely on overlapping * mappings for PCS. @@ -2779,18 +2244,9 @@ static const struct of_device_id qmp_usb_of_match_table[] = { }, { .compatible = "qcom,sa8775p-qmp-usb3-uni-phy", .data = &sa8775p_usb3_uniphy_cfg, - }, { - .compatible = "qcom,sc7180-qmp-usb3-phy", - .data = &sc7180_usb3phy_cfg, - }, { - .compatible = "qcom,sc8180x-qmp-usb3-phy", - .data = &sm8150_usb3phy_cfg, }, { .compatible = "qcom,sc8280xp-qmp-usb3-uni-phy", .data = &sc8280xp_usb3_uniphy_cfg, - }, { - .compatible = "qcom,sdm845-qmp-usb3-phy", - .data = &qmp_v3_usb3phy_cfg, }, { .compatible = "qcom,sdm845-qmp-usb3-uni-phy", .data = &qmp_v3_usb3_uniphy_cfg, @@ -2803,27 +2259,15 @@ static const struct of_device_id qmp_usb_of_match_table[] = { }, { .compatible = "qcom,sm6115-qmp-usb3-phy", .data = &qcm2290_usb3phy_cfg, - }, { - .compatible = "qcom,sm8150-qmp-usb3-phy", - .data = &sm8150_usb3phy_cfg, }, { .compatible = "qcom,sm8150-qmp-usb3-uni-phy", .data = &sm8150_usb3_uniphy_cfg, - }, { - .compatible = "qcom,sm8250-qmp-usb3-phy", - .data = &sm8250_usb3phy_cfg, }, { .compatible = "qcom,sm8250-qmp-usb3-uni-phy", .data = &sm8250_usb3_uniphy_cfg, - }, { - .compatible = "qcom,sm8350-qmp-usb3-phy", - .data = &sm8350_usb3phy_cfg, }, { .compatible = "qcom,sm8350-qmp-usb3-uni-phy", .data = &sm8350_usb3_uniphy_cfg, - }, { - .compatible = "qcom,sm8450-qmp-usb3-phy", - .data = &sm8350_usb3phy_cfg, }, { }, }; -- GitLab From 94255d981f63fd106ed4f72abd26174ca55f84fa Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 25 May 2023 13:52:56 +0200 Subject: [PATCH 0145/3445] phy: mediatek: mipi-dsi: Convert to register clk_hw Instead of registering a struct clk, directly register clk_hw: this allows us to cleanup a pointer to struct clk from struct mtk_mipi_tx. Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230525115258.90091-2-angelogioacchino.delregno@collabora.com Signed-off-by: Vinod Koul --- drivers/phy/mediatek/phy-mtk-mipi-dsi.c | 13 ++++++------- drivers/phy/mediatek/phy-mtk-mipi-dsi.h | 1 - 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c index 526c05a4af5e6..362145198ff5d 100644 --- a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c +++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c @@ -36,7 +36,7 @@ static int mtk_mipi_tx_power_on(struct phy *phy) int ret; /* Power up core and enable PLL */ - ret = clk_prepare_enable(mipi_tx->pll); + ret = clk_prepare_enable(mipi_tx->pll_hw.clk); if (ret < 0) return ret; @@ -53,7 +53,7 @@ static int mtk_mipi_tx_power_off(struct phy *phy) mipi_tx->driver_data->mipi_tx_disable_signal(phy); /* Disable PLL and power down core */ - clk_disable_unprepare(mipi_tx->pll); + clk_disable_unprepare(mipi_tx->pll_hw.clk); return 0; } @@ -158,9 +158,9 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev) clk_init.ops = mipi_tx->driver_data->mipi_tx_clk_ops; mipi_tx->pll_hw.init = &clk_init; - mipi_tx->pll = devm_clk_register(dev, &mipi_tx->pll_hw); - if (IS_ERR(mipi_tx->pll)) - return dev_err_probe(dev, PTR_ERR(mipi_tx->pll), "Failed to register PLL\n"); + ret = devm_clk_hw_register(dev, &mipi_tx->pll_hw); + if (ret) + return dev_err_probe(dev, ret, "Failed to register PLL\n"); phy = devm_phy_create(dev, NULL, &mtk_mipi_tx_ops); if (IS_ERR(phy)) @@ -176,8 +176,7 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev) mtk_mipi_tx_get_calibration_datal(mipi_tx); - return of_clk_add_provider(dev->of_node, of_clk_src_simple_get, - mipi_tx->pll); + return of_clk_add_hw_provider(dev->of_node, of_clk_hw_simple_get, &mipi_tx->pll_hw); } static void mtk_mipi_tx_remove(struct platform_device *pdev) diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi.h b/drivers/phy/mediatek/phy-mtk-mipi-dsi.h index 47b60b1a72261..0250c4a454e7b 100644 --- a/drivers/phy/mediatek/phy-mtk-mipi-dsi.h +++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi.h @@ -32,7 +32,6 @@ struct mtk_mipi_tx { u32 rt_code[5]; const struct mtk_mipitx_data *driver_data; struct clk_hw pll_hw; - struct clk *pll; }; struct mtk_mipi_tx *mtk_mipi_tx_from_clk_hw(struct clk_hw *hw); -- GitLab From e90da3fc82f4e3bc86e29ca89ea6cceb5dcd3613 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 25 May 2023 13:52:57 +0200 Subject: [PATCH 0146/3445] phy: mediatek: mipi-dsi: Use devm variant for of_clk_add_hw_provider() Switch to devm_of_clk_add_hw_provider() in the probe function: this also allows to entirely remove the .remove_new() callback, as its only task was to unregister the clock provider. Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230525115258.90091-3-angelogioacchino.delregno@collabora.com Signed-off-by: Vinod Koul --- drivers/phy/mediatek/phy-mtk-mipi-dsi.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c index 362145198ff5d..4e75c34c819b5 100644 --- a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c +++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c @@ -176,12 +176,7 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev) mtk_mipi_tx_get_calibration_datal(mipi_tx); - return of_clk_add_hw_provider(dev->of_node, of_clk_hw_simple_get, &mipi_tx->pll_hw); -} - -static void mtk_mipi_tx_remove(struct platform_device *pdev) -{ - of_clk_del_provider(pdev->dev.of_node); + return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &mipi_tx->pll_hw); } static const struct of_device_id mtk_mipi_tx_match[] = { @@ -197,7 +192,6 @@ MODULE_DEVICE_TABLE(of, mtk_mipi_tx_match); static struct platform_driver mtk_mipi_tx_driver = { .probe = mtk_mipi_tx_probe, - .remove_new = mtk_mipi_tx_remove, .driver = { .name = "mediatek-mipi-tx", .of_match_table = mtk_mipi_tx_match, -- GitLab From bd36b1ba2010714b5f1e77e6648973392939e1d6 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 25 May 2023 13:52:58 +0200 Subject: [PATCH 0147/3445] phy: mediatek: mipi-dsi: Compress of_device_id match entries All of the entries do fit in a maximum of 82 columns, which is acceptable. While at it, also remove the useless comma on the last entry and add the usual sentinel comment. Signed-off-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230525115258.90091-4-angelogioacchino.delregno@collabora.com Signed-off-by: Vinod Koul --- drivers/phy/mediatek/phy-mtk-mipi-dsi.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c index 4e75c34c819b5..065ea626093aa 100644 --- a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c +++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c @@ -180,13 +180,10 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev) } static const struct of_device_id mtk_mipi_tx_match[] = { - { .compatible = "mediatek,mt2701-mipi-tx", - .data = &mt2701_mipitx_data }, - { .compatible = "mediatek,mt8173-mipi-tx", - .data = &mt8173_mipitx_data }, - { .compatible = "mediatek,mt8183-mipi-tx", - .data = &mt8183_mipitx_data }, - { }, + { .compatible = "mediatek,mt2701-mipi-tx", .data = &mt2701_mipitx_data }, + { .compatible = "mediatek,mt8173-mipi-tx", .data = &mt8173_mipitx_data }, + { .compatible = "mediatek,mt8183-mipi-tx", .data = &mt8183_mipitx_data }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, mtk_mipi_tx_match); -- GitLab From b3db66f624468ab4a0385586bc7f4221e477d6b2 Mon Sep 17 00:00:00 2001 From: Piyush Mehta Date: Tue, 13 Jun 2023 19:32:49 +0530 Subject: [PATCH 0148/3445] phy: xilinx: add runtime PM support Added Runtime power management support to the xilinx phy driver and using DEFINE_RUNTIME_DEV_PM_OPS new macros allows the compiler to remove the unused dev_pm_ops structure and related functions if !CONFIG_PM without the need to mark the functions __maybe_unused. Signed-off-by: Piyush Mehta Link: https://lore.kernel.org/r/20230613140250.3018947-2-piyush.mehta@amd.com Signed-off-by: Vinod Koul --- drivers/phy/xilinx/phy-zynqmp.c | 35 ++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/drivers/phy/xilinx/phy-zynqmp.c b/drivers/phy/xilinx/phy-zynqmp.c index 8833680923a14..aada18123c193 100644 --- a/drivers/phy/xilinx/phy-zynqmp.c +++ b/drivers/phy/xilinx/phy-zynqmp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -820,7 +821,7 @@ static struct phy *xpsgtr_xlate(struct device *dev, * Power Management */ -static int __maybe_unused xpsgtr_suspend(struct device *dev) +static int xpsgtr_runtime_suspend(struct device *dev) { struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev); unsigned int i; @@ -835,7 +836,7 @@ static int __maybe_unused xpsgtr_suspend(struct device *dev) return 0; } -static int __maybe_unused xpsgtr_resume(struct device *dev) +static int xpsgtr_runtime_resume(struct device *dev) { struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev); unsigned int icm_cfg0, icm_cfg1; @@ -876,10 +877,8 @@ err_clk_put: return err; } -static const struct dev_pm_ops xpsgtr_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(xpsgtr_suspend, xpsgtr_resume) -}; - +static DEFINE_RUNTIME_DEV_PM_OPS(xpsgtr_pm_ops, xpsgtr_runtime_suspend, + xpsgtr_runtime_resume, NULL); /* * Probe & Platform Driver */ @@ -1005,6 +1004,16 @@ static int xpsgtr_probe(struct platform_device *pdev) ret = PTR_ERR(provider); goto err_clk_put; } + + pm_runtime_set_active(gtr_dev->dev); + pm_runtime_enable(gtr_dev->dev); + + ret = pm_runtime_resume_and_get(gtr_dev->dev); + if (ret < 0) { + pm_runtime_disable(gtr_dev->dev); + goto err_clk_put; + } + return 0; err_clk_put: @@ -1014,6 +1023,17 @@ err_clk_put: return ret; } +static int xpsgtr_remove(struct platform_device *pdev) +{ + struct xpsgtr_dev *gtr_dev = platform_get_drvdata(pdev); + + pm_runtime_disable(gtr_dev->dev); + pm_runtime_put_noidle(gtr_dev->dev); + pm_runtime_set_suspended(gtr_dev->dev); + + return 0; +} + static const struct of_device_id xpsgtr_of_match[] = { { .compatible = "xlnx,zynqmp-psgtr", }, { .compatible = "xlnx,zynqmp-psgtr-v1.1", }, @@ -1023,10 +1043,11 @@ MODULE_DEVICE_TABLE(of, xpsgtr_of_match); static struct platform_driver xpsgtr_driver = { .probe = xpsgtr_probe, + .remove = xpsgtr_remove, .driver = { .name = "xilinx-psgtr", .of_match_table = xpsgtr_of_match, - .pm = &xpsgtr_pm_ops, + .pm = pm_ptr(&xpsgtr_pm_ops), }, }; -- GitLab From 25d70083351318b44ae699d92c042dcb18a738ea Mon Sep 17 00:00:00 2001 From: Piyush Mehta Date: Tue, 13 Jun 2023 19:32:50 +0530 Subject: [PATCH 0149/3445] phy: xilinx: phy-zynqmp: dynamic clock support for power-save Enabling clock for all the lanes consumes power even PHY is active or inactive. To resolve this, enable/disable clocks in phy_init/phy_exit. By default clock is disabled for all the lanes. Whenever phy_init called from USB, SATA, or display driver, etc. It enabled the required clock for requested lane. On phy_exit cycle, it disabled clock for the active PHYs. During the suspend/resume cycle, each USB/ SATA/ display driver called phy_exit/phy_init individually. It disabled clock on exit, and enabled on initialization for the active PHYs. Signed-off-by: Piyush Mehta Link: https://lore.kernel.org/r/20230613140250.3018947-3-piyush.mehta@amd.com Signed-off-by: Vinod Koul --- drivers/phy/xilinx/phy-zynqmp.c | 61 ++++++++------------------------- 1 file changed, 15 insertions(+), 46 deletions(-) diff --git a/drivers/phy/xilinx/phy-zynqmp.c b/drivers/phy/xilinx/phy-zynqmp.c index aada18123c193..b0c2045b886ee 100644 --- a/drivers/phy/xilinx/phy-zynqmp.c +++ b/drivers/phy/xilinx/phy-zynqmp.c @@ -572,6 +572,10 @@ static int xpsgtr_phy_init(struct phy *phy) mutex_lock(>r_dev->gtr_mutex); + /* Configure and enable the clock when peripheral phy_init call */ + if (clk_prepare_enable(gtr_dev->clk[gtr_phy->lane])) + goto out; + /* Skip initialization if not required. */ if (!xpsgtr_phy_init_required(gtr_phy)) goto out; @@ -616,9 +620,13 @@ out: static int xpsgtr_phy_exit(struct phy *phy) { struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy); + struct xpsgtr_dev *gtr_dev = gtr_phy->dev; gtr_phy->skip_phy_init = false; + /* Ensure that disable clock only, which configure for lane */ + clk_disable_unprepare(gtr_dev->clk[gtr_phy->lane]); + return 0; } @@ -824,15 +832,11 @@ static struct phy *xpsgtr_xlate(struct device *dev, static int xpsgtr_runtime_suspend(struct device *dev) { struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev); - unsigned int i; /* Save the snapshot ICM_CFG registers. */ gtr_dev->saved_icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0); gtr_dev->saved_icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1); - for (i = 0; i < ARRAY_SIZE(gtr_dev->clk); i++) - clk_disable_unprepare(gtr_dev->clk[i]); - return 0; } @@ -842,13 +846,6 @@ static int xpsgtr_runtime_resume(struct device *dev) unsigned int icm_cfg0, icm_cfg1; unsigned int i; bool skip_phy_init; - int err; - - for (i = 0; i < ARRAY_SIZE(gtr_dev->clk); i++) { - err = clk_prepare_enable(gtr_dev->clk[i]); - if (err) - goto err_clk_put; - } icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0); icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1); @@ -869,12 +866,6 @@ static int xpsgtr_runtime_resume(struct device *dev) gtr_dev->phys[i].skip_phy_init = skip_phy_init; return 0; - -err_clk_put: - while (i--) - clk_disable_unprepare(gtr_dev->clk[i]); - - return err; } static DEFINE_RUNTIME_DEV_PM_OPS(xpsgtr_pm_ops, xpsgtr_runtime_suspend, @@ -886,7 +877,6 @@ static DEFINE_RUNTIME_DEV_PM_OPS(xpsgtr_pm_ops, xpsgtr_runtime_suspend, static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev) { unsigned int refclk; - int ret; for (refclk = 0; refclk < ARRAY_SIZE(gtr_dev->refclk_sscs); ++refclk) { unsigned long rate; @@ -897,19 +887,14 @@ static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev) snprintf(name, sizeof(name), "ref%u", refclk); clk = devm_clk_get_optional(gtr_dev->dev, name); if (IS_ERR(clk)) { - ret = dev_err_probe(gtr_dev->dev, PTR_ERR(clk), - "Failed to get reference clock %u\n", - refclk); - goto err_clk_put; + return dev_err_probe(gtr_dev->dev, PTR_ERR(clk), + "Failed to get ref clock %u\n", + refclk); } if (!clk) continue; - ret = clk_prepare_enable(clk); - if (ret) - goto err_clk_put; - gtr_dev->clk[refclk] = clk; /* @@ -929,18 +914,11 @@ static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev) dev_err(gtr_dev->dev, "Invalid rate %lu for reference clock %u\n", rate, refclk); - ret = -EINVAL; - goto err_clk_put; + return -EINVAL; } } return 0; - -err_clk_put: - while (refclk--) - clk_disable_unprepare(gtr_dev->clk[refclk]); - - return ret; } static int xpsgtr_probe(struct platform_device *pdev) @@ -949,7 +927,6 @@ static int xpsgtr_probe(struct platform_device *pdev) struct xpsgtr_dev *gtr_dev; struct phy_provider *provider; unsigned int port; - unsigned int i; int ret; gtr_dev = devm_kzalloc(&pdev->dev, sizeof(*gtr_dev), GFP_KERNEL); @@ -989,8 +966,7 @@ static int xpsgtr_probe(struct platform_device *pdev) phy = devm_phy_create(&pdev->dev, np, &xpsgtr_phyops); if (IS_ERR(phy)) { dev_err(&pdev->dev, "failed to create PHY\n"); - ret = PTR_ERR(phy); - goto err_clk_put; + return PTR_ERR(phy); } gtr_phy->phy = phy; @@ -1001,8 +977,7 @@ static int xpsgtr_probe(struct platform_device *pdev) provider = devm_of_phy_provider_register(&pdev->dev, xpsgtr_xlate); if (IS_ERR(provider)) { dev_err(&pdev->dev, "registering provider failed\n"); - ret = PTR_ERR(provider); - goto err_clk_put; + return PTR_ERR(provider); } pm_runtime_set_active(gtr_dev->dev); @@ -1011,16 +986,10 @@ static int xpsgtr_probe(struct platform_device *pdev) ret = pm_runtime_resume_and_get(gtr_dev->dev); if (ret < 0) { pm_runtime_disable(gtr_dev->dev); - goto err_clk_put; + return ret; } return 0; - -err_clk_put: - for (i = 0; i < ARRAY_SIZE(gtr_dev->clk); i++) - clk_disable_unprepare(gtr_dev->clk[i]); - - return ret; } static int xpsgtr_remove(struct platform_device *pdev) -- GitLab From 6292fd920ee76f3e95fb580ced44831884942e05 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 21 Jun 2023 18:33:11 +0300 Subject: [PATCH 0150/3445] phy: qcom: qmp-combo: correct bias0_en programming It seems the commit a2e927b0e50d ("phy: qcom-qmp-combo: Add sc8280xp USB/DP combo phys") contained a typo for selecting bias0_en values. First, bias0_en and bias1_en are expected to be symmetrical, and then the vendor driver also uses `flipped : 0x3E : 0x15` statement for bias0_en. Correct bias0_en programming to follow this. Fixes: 49742e9edab3 ("phy: qcom-qmp-combo: Add support for SM8550") Fixes: a2e927b0e50d ("phy: qcom-qmp-combo: Add sc8280xp USB/DP combo phys") Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230621153317.1025914-2-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index d4f271b3c2117..641307f6ee290 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -2322,7 +2322,7 @@ static int qmp_v5_configure_dp_phy(struct qmp_combo *qmp) return ret; if (dp_opts->lanes == 1) { - bias0_en = reverse ? 0x3e : 0x1a; + bias0_en = reverse ? 0x3e : 0x15; drvr0_en = reverse ? 0x13 : 0x10; bias1_en = reverse ? 0x15 : 0x3e; drvr1_en = reverse ? 0x10 : 0x13; @@ -2382,7 +2382,7 @@ static int qmp_v6_configure_dp_phy(struct qmp_combo *qmp) return ret; if (dp_opts->lanes == 1) { - bias0_en = reverse ? 0x3e : 0x1a; + bias0_en = reverse ? 0x3e : 0x15; drvr0_en = reverse ? 0x13 : 0x10; bias1_en = reverse ? 0x15 : 0x3e; drvr1_en = reverse ? 0x10 : 0x13; -- GitLab From 8447fa7f7e6a029a5f4381d42f8b6a6c5581628e Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 21 Jun 2023 18:33:12 +0300 Subject: [PATCH 0151/3445] phy: qcom: qmp-combo: reuse register layouts for more registers Instead of passing additional registers to qmp_v456_configure_dp_phy(), reuse qphy_reg_layout and add those registers to register layout maps. Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230621153317.1025914-3-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 100 ++++++++++++++-------- 1 file changed, 64 insertions(+), 36 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index 641307f6ee290..22f073c3d03f7 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -106,6 +106,13 @@ enum qphy_reg_layout { QPHY_PCS_AUTONOMOUS_MODE_CTRL, QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR, QPHY_PCS_POWER_DOWN_CONTROL, + + QPHY_COM_RESETSM_CNTRL, + QPHY_COM_C_READY_STATUS, + QPHY_COM_CMN_STATUS, + + QPHY_DP_PHY_STATUS, + /* Keep last to ensure regs_layout arrays are properly initialized */ QPHY_LAYOUT_SIZE }; @@ -117,9 +124,15 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V3_PCS_POWER_DOWN_CONTROL, [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V3_PCS_AUTONOMOUS_MODE_CTRL, [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V3_PCS_LFPS_RXTERM_IRQ_CLEAR, + + [QPHY_COM_RESETSM_CNTRL] = QSERDES_V3_COM_RESETSM_CNTRL, + [QPHY_COM_C_READY_STATUS] = QSERDES_V3_COM_C_READY_STATUS, + [QPHY_COM_CMN_STATUS] = QSERDES_V3_COM_CMN_STATUS, + + [QPHY_DP_PHY_STATUS] = QSERDES_V3_DP_PHY_STATUS, }; -static const unsigned int qmp_v4_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { +static const unsigned int qmp_v45_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_SW_RESET] = QPHY_V4_PCS_SW_RESET, [QPHY_START_CTRL] = QPHY_V4_PCS_START_CONTROL, [QPHY_PCS_STATUS] = QPHY_V4_PCS_PCS_STATUS1, @@ -128,6 +141,29 @@ static const unsigned int qmp_v4_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { /* In PCS_USB */ [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V4_PCS_USB3_AUTONOMOUS_MODE_CTRL, [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V4_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR, + + [QPHY_COM_RESETSM_CNTRL] = QSERDES_V4_COM_RESETSM_CNTRL, + [QPHY_COM_C_READY_STATUS] = QSERDES_V4_COM_C_READY_STATUS, + [QPHY_COM_CMN_STATUS] = QSERDES_V4_COM_CMN_STATUS, + + [QPHY_DP_PHY_STATUS] = QSERDES_V4_DP_PHY_STATUS, +}; + +static const unsigned int qmp_v6_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_SW_RESET] = QPHY_V5_PCS_SW_RESET, + [QPHY_START_CTRL] = QPHY_V5_PCS_START_CONTROL, + [QPHY_PCS_STATUS] = QPHY_V5_PCS_PCS_STATUS1, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V5_PCS_POWER_DOWN_CONTROL, + + /* In PCS_USB */ + [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V5_PCS_USB3_AUTONOMOUS_MODE_CTRL, + [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V5_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR, + + [QPHY_COM_RESETSM_CNTRL] = QSERDES_V6_COM_RESETSM_CNTRL, + [QPHY_COM_C_READY_STATUS] = QSERDES_V6_COM_C_READY_STATUS, + [QPHY_COM_CMN_STATUS] = QSERDES_V6_COM_CMN_STATUS, + + [QPHY_DP_PHY_STATUS] = QSERDES_V6_DP_PHY_STATUS, }; static const struct qmp_phy_init_tbl qmp_v3_usb3_serdes_tbl[] = { @@ -1564,7 +1600,7 @@ static const struct qmp_phy_cfg sc8180x_usb3dpphy_cfg = { .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), - .regs = qmp_v4_usb3phy_regs_layout, + .regs = qmp_v45_usb3phy_regs_layout, .pcs_usb_offset = 0x300, .has_pwrdn_delay = true, @@ -1612,7 +1648,7 @@ static const struct qmp_phy_cfg sc8280xp_usb43dpphy_cfg = { .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), - .regs = qmp_v4_usb3phy_regs_layout, + .regs = qmp_v45_usb3phy_regs_layout, }; static const struct qmp_phy_cfg sm6350_usb3dpphy_cfg = { @@ -1702,7 +1738,7 @@ static const struct qmp_phy_cfg sm8250_usb3dpphy_cfg = { .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), - .regs = qmp_v4_usb3phy_regs_layout, + .regs = qmp_v45_usb3phy_regs_layout, .pcs_usb_offset = 0x300, .has_pwrdn_delay = true, @@ -1752,7 +1788,7 @@ static const struct qmp_phy_cfg sm8350_usb3dpphy_cfg = { .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), - .regs = qmp_v4_usb3phy_regs_layout, + .regs = qmp_v45_usb3phy_regs_layout, .has_pwrdn_delay = true, }; @@ -1795,7 +1831,7 @@ static const struct qmp_phy_cfg sm8550_usb3dpphy_cfg = { .configure_dp_phy = qmp_v6_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, - .regs = qmp_v4_usb3phy_regs_layout, + .regs = qmp_v6_usb3phy_regs_layout, .clk_list = qmp_v4_phy_clk_l, .num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l), .reset_list = msm8996_usb3phy_reset_l, @@ -1994,6 +2030,7 @@ static bool qmp_combo_configure_dp_mode(struct qmp_combo *qmp) static int qmp_v3_configure_dp_phy(struct qmp_combo *qmp) { const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; + const struct qmp_phy_cfg *cfg = qmp->cfg; u32 phy_vco_div, status; unsigned long pixel_freq; @@ -2034,9 +2071,9 @@ static int qmp_v3_configure_dp_phy(struct qmp_combo *qmp) writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); writel(0x09, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); - writel(0x20, qmp->dp_serdes + QSERDES_V3_COM_RESETSM_CNTRL); + writel(0x20, qmp->dp_serdes + cfg->regs[QPHY_COM_RESETSM_CNTRL]); - if (readl_poll_timeout(qmp->dp_serdes + QSERDES_V3_COM_C_READY_STATUS, + if (readl_poll_timeout(qmp->dp_serdes + cfg->regs[QPHY_COM_C_READY_STATUS], status, ((status & BIT(0)) > 0), 500, @@ -2045,7 +2082,7 @@ static int qmp_v3_configure_dp_phy(struct qmp_combo *qmp) writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); - if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V3_DP_PHY_STATUS, + if (readl_poll_timeout(qmp->dp_dp_phy + cfg->regs[QPHY_DP_PHY_STATUS], status, ((status & BIT(1)) > 0), 500, @@ -2056,7 +2093,7 @@ static int qmp_v3_configure_dp_phy(struct qmp_combo *qmp) udelay(2000); writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); - return readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V3_DP_PHY_STATUS, + return readl_poll_timeout(qmp->dp_dp_phy + cfg->regs[QPHY_DP_PHY_STATUS], status, ((status & BIT(1)) > 0), 500, @@ -2148,13 +2185,10 @@ static void qmp_v4_configure_dp_tx(struct qmp_combo *qmp) QSERDES_V4_TX_TX_EMP_POST1_LVL); } -static int qmp_v456_configure_dp_phy(struct qmp_combo *qmp, - unsigned int com_resetm_ctrl_reg, - unsigned int com_c_ready_status_reg, - unsigned int com_cmn_status_reg, - unsigned int dp_phy_status_reg) +static int qmp_v456_configure_dp_phy(struct qmp_combo *qmp) { const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; + const struct qmp_phy_cfg *cfg = qmp->cfg; u32 phy_vco_div, status; unsigned long pixel_freq; @@ -2199,23 +2233,23 @@ static int qmp_v456_configure_dp_phy(struct qmp_combo *qmp, writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); writel(0x09, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); - writel(0x20, qmp->dp_serdes + com_resetm_ctrl_reg); + writel(0x20, qmp->dp_serdes + cfg->regs[QPHY_COM_RESETSM_CNTRL]); - if (readl_poll_timeout(qmp->dp_serdes + com_c_ready_status_reg, + if (readl_poll_timeout(qmp->dp_serdes + cfg->regs[QPHY_COM_C_READY_STATUS], status, ((status & BIT(0)) > 0), 500, 10000)) return -ETIMEDOUT; - if (readl_poll_timeout(qmp->dp_serdes + com_cmn_status_reg, + if (readl_poll_timeout(qmp->dp_serdes + cfg->regs[QPHY_COM_CMN_STATUS], status, ((status & BIT(0)) > 0), 500, 10000)) return -ETIMEDOUT; - if (readl_poll_timeout(qmp->dp_serdes + com_cmn_status_reg, + if (readl_poll_timeout(qmp->dp_serdes + cfg->regs[QPHY_COM_CMN_STATUS], status, ((status & BIT(1)) > 0), 500, @@ -2224,14 +2258,14 @@ static int qmp_v456_configure_dp_phy(struct qmp_combo *qmp, writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); - if (readl_poll_timeout(qmp->dp_dp_phy + dp_phy_status_reg, + if (readl_poll_timeout(qmp->dp_dp_phy + cfg->regs[QPHY_DP_PHY_STATUS], status, ((status & BIT(0)) > 0), 500, 10000)) return -ETIMEDOUT; - if (readl_poll_timeout(qmp->dp_dp_phy + dp_phy_status_reg, + if (readl_poll_timeout(qmp->dp_dp_phy + cfg->regs[QPHY_DP_PHY_STATUS], status, ((status & BIT(1)) > 0), 500, @@ -2243,16 +2277,14 @@ static int qmp_v456_configure_dp_phy(struct qmp_combo *qmp, static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp) { + const struct qmp_phy_cfg *cfg = qmp->cfg; bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE); const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; u32 bias0_en, drvr0_en, bias1_en, drvr1_en; u32 status; int ret; - ret = qmp_v456_configure_dp_phy(qmp, QSERDES_V4_COM_RESETSM_CNTRL, - QSERDES_V4_COM_C_READY_STATUS, - QSERDES_V4_COM_CMN_STATUS, - QSERDES_V4_DP_PHY_STATUS); + ret = qmp_v456_configure_dp_phy(qmp); if (ret < 0) return ret; @@ -2287,7 +2319,7 @@ static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp) udelay(2000); writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); - if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V4_DP_PHY_STATUS, + if (readl_poll_timeout(qmp->dp_dp_phy + cfg->regs[QPHY_DP_PHY_STATUS], status, ((status & BIT(1)) > 0), 500, @@ -2308,16 +2340,14 @@ static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp) static int qmp_v5_configure_dp_phy(struct qmp_combo *qmp) { + const struct qmp_phy_cfg *cfg = qmp->cfg; bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE); const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; u32 bias0_en, drvr0_en, bias1_en, drvr1_en; u32 status; int ret; - ret = qmp_v456_configure_dp_phy(qmp, QSERDES_V4_COM_RESETSM_CNTRL, - QSERDES_V4_COM_C_READY_STATUS, - QSERDES_V4_COM_CMN_STATUS, - QSERDES_V4_DP_PHY_STATUS); + ret = qmp_v456_configure_dp_phy(qmp); if (ret < 0) return ret; @@ -2347,7 +2377,7 @@ static int qmp_v5_configure_dp_phy(struct qmp_combo *qmp) udelay(2000); writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); - if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V4_DP_PHY_STATUS, + if (readl_poll_timeout(qmp->dp_dp_phy + cfg->regs[QPHY_DP_PHY_STATUS], status, ((status & BIT(1)) > 0), 500, @@ -2368,16 +2398,14 @@ static int qmp_v5_configure_dp_phy(struct qmp_combo *qmp) static int qmp_v6_configure_dp_phy(struct qmp_combo *qmp) { + const struct qmp_phy_cfg *cfg = qmp->cfg; bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE); const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; u32 bias0_en, drvr0_en, bias1_en, drvr1_en; u32 status; int ret; - ret = qmp_v456_configure_dp_phy(qmp, QSERDES_V6_COM_RESETSM_CNTRL, - QSERDES_V6_COM_C_READY_STATUS, - QSERDES_V6_COM_CMN_STATUS, - QSERDES_V6_DP_PHY_STATUS); + ret = qmp_v456_configure_dp_phy(qmp); if (ret < 0) return ret; @@ -2407,7 +2435,7 @@ static int qmp_v6_configure_dp_phy(struct qmp_combo *qmp) udelay(2000); writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); - if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V6_DP_PHY_STATUS, + if (readl_poll_timeout(qmp->dp_dp_phy + cfg->regs[QPHY_DP_PHY_STATUS], status, ((status & BIT(1)) > 0), 500, -- GitLab From 186ad90aa49fb9222f48474d7482996c8279c077 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 21 Jun 2023 18:33:13 +0300 Subject: [PATCH 0152/3445] phy: qcom: qmp-combo: reuse register layouts for even more registers Instead of passing additional registers to qmp_combo_configure_dp_swing(), reuse qphy_reg_layout and add those registers to register layout maps. Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230621153317.1025914-4-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 104 ++++++++++++------ .../qualcomm/phy-qcom-qmp-qserdes-txrx-v6.h | 3 + drivers/phy/qualcomm/phy-qcom-qmp.h | 2 + 3 files changed, 76 insertions(+), 33 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index 22f073c3d03f7..8dd00a1bb9035 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -113,6 +113,10 @@ enum qphy_reg_layout { QPHY_DP_PHY_STATUS, + QPHY_TX_TX_POL_INV, + QPHY_TX_TX_DRV_LVL, + QPHY_TX_TX_EMP_POST1_LVL, + /* Keep last to ensure regs_layout arrays are properly initialized */ QPHY_LAYOUT_SIZE }; @@ -130,6 +134,10 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_COM_CMN_STATUS] = QSERDES_V3_COM_CMN_STATUS, [QPHY_DP_PHY_STATUS] = QSERDES_V3_DP_PHY_STATUS, + + [QPHY_TX_TX_POL_INV] = QSERDES_V3_TX_TX_POL_INV, + [QPHY_TX_TX_DRV_LVL] = QSERDES_V3_TX_TX_DRV_LVL, + [QPHY_TX_TX_EMP_POST1_LVL] = QSERDES_V3_TX_TX_EMP_POST1_LVL, }; static const unsigned int qmp_v45_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { @@ -147,6 +155,31 @@ static const unsigned int qmp_v45_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_COM_CMN_STATUS] = QSERDES_V4_COM_CMN_STATUS, [QPHY_DP_PHY_STATUS] = QSERDES_V4_DP_PHY_STATUS, + + [QPHY_TX_TX_POL_INV] = QSERDES_V4_TX_TX_POL_INV, + [QPHY_TX_TX_DRV_LVL] = QSERDES_V4_TX_TX_DRV_LVL, + [QPHY_TX_TX_EMP_POST1_LVL] = QSERDES_V4_TX_TX_EMP_POST1_LVL, +}; + +static const unsigned int qmp_v5_5nm_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_SW_RESET] = QPHY_V5_PCS_SW_RESET, + [QPHY_START_CTRL] = QPHY_V5_PCS_START_CONTROL, + [QPHY_PCS_STATUS] = QPHY_V5_PCS_PCS_STATUS1, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V5_PCS_POWER_DOWN_CONTROL, + + /* In PCS_USB */ + [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V5_PCS_USB3_AUTONOMOUS_MODE_CTRL, + [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V5_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR, + + [QPHY_COM_RESETSM_CNTRL] = QSERDES_V5_COM_RESETSM_CNTRL, + [QPHY_COM_C_READY_STATUS] = QSERDES_V5_COM_C_READY_STATUS, + [QPHY_COM_CMN_STATUS] = QSERDES_V5_COM_CMN_STATUS, + + [QPHY_DP_PHY_STATUS] = QSERDES_V5_DP_PHY_STATUS, + + [QPHY_TX_TX_POL_INV] = QSERDES_V5_5NM_TX_TX_POL_INV, + [QPHY_TX_TX_DRV_LVL] = QSERDES_V5_5NM_TX_TX_DRV_LVL, + [QPHY_TX_TX_EMP_POST1_LVL] = QSERDES_V5_5NM_TX_TX_EMP_POST1_LVL, }; static const unsigned int qmp_v6_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { @@ -164,6 +197,10 @@ static const unsigned int qmp_v6_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_COM_CMN_STATUS] = QSERDES_V6_COM_CMN_STATUS, [QPHY_DP_PHY_STATUS] = QSERDES_V6_DP_PHY_STATUS, + + [QPHY_TX_TX_POL_INV] = QSERDES_V6_TX_TX_POL_INV, + [QPHY_TX_TX_DRV_LVL] = QSERDES_V6_TX_TX_DRV_LVL, + [QPHY_TX_TX_EMP_POST1_LVL] = QSERDES_V6_TX_TX_EMP_POST1_LVL, }; static const struct qmp_phy_init_tbl qmp_v3_usb3_serdes_tbl[] = { @@ -1648,7 +1685,7 @@ static const struct qmp_phy_cfg sc8280xp_usb43dpphy_cfg = { .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), - .regs = qmp_v45_usb3phy_regs_layout, + .regs = qmp_v5_5nm_usb3phy_regs_layout, }; static const struct qmp_phy_cfg sm6350_usb3dpphy_cfg = { @@ -1942,8 +1979,7 @@ static void qmp_v3_dp_aux_init(struct qmp_combo *qmp) qmp->dp_dp_phy + QSERDES_V3_DP_PHY_AUX_INTERRUPT_MASK); } -static int qmp_combo_configure_dp_swing(struct qmp_combo *qmp, - unsigned int drv_lvl_reg, unsigned int emp_post_reg) +static int qmp_combo_configure_dp_swing(struct qmp_combo *qmp) { const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -1972,10 +2008,10 @@ static int qmp_combo_configure_dp_swing(struct qmp_combo *qmp, voltage_swing_cfg |= DP_PHY_TXn_TX_DRV_LVL_MUX_EN; pre_emphasis_cfg |= DP_PHY_TXn_TX_EMP_POST1_LVL_MUX_EN; - writel(voltage_swing_cfg, qmp->dp_tx + drv_lvl_reg); - writel(pre_emphasis_cfg, qmp->dp_tx + emp_post_reg); - writel(voltage_swing_cfg, qmp->dp_tx2 + drv_lvl_reg); - writel(pre_emphasis_cfg, qmp->dp_tx2 + emp_post_reg); + writel(voltage_swing_cfg, qmp->dp_tx + cfg->regs[QPHY_TX_TX_DRV_LVL]); + writel(pre_emphasis_cfg, qmp->dp_tx + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); + writel(voltage_swing_cfg, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_DRV_LVL]); + writel(pre_emphasis_cfg, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); return 0; } @@ -1985,8 +2021,7 @@ static void qmp_v3_configure_dp_tx(struct qmp_combo *qmp) const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; u32 bias_en, drvr_en; - if (qmp_combo_configure_dp_swing(qmp, QSERDES_V3_TX_TX_DRV_LVL, - QSERDES_V3_TX_TX_EMP_POST1_LVL) < 0) + if (qmp_combo_configure_dp_swing(qmp) < 0) return; if (dp_opts->lanes == 1) { @@ -2174,15 +2209,16 @@ static void qmp_v6_dp_aux_init(struct qmp_combo *qmp) static void qmp_v4_configure_dp_tx(struct qmp_combo *qmp) { + const struct qmp_phy_cfg *cfg = qmp->cfg; + /* Program default values before writing proper values */ - writel(0x27, qmp->dp_tx + QSERDES_V4_TX_TX_DRV_LVL); - writel(0x27, qmp->dp_tx2 + QSERDES_V4_TX_TX_DRV_LVL); + writel(0x27, qmp->dp_tx + cfg->regs[QPHY_TX_TX_DRV_LVL]); + writel(0x27, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_DRV_LVL]); - writel(0x20, qmp->dp_tx + QSERDES_V4_TX_TX_EMP_POST1_LVL); - writel(0x20, qmp->dp_tx2 + QSERDES_V4_TX_TX_EMP_POST1_LVL); + writel(0x20, qmp->dp_tx + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); + writel(0x20, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); - qmp_combo_configure_dp_swing(qmp, QSERDES_V4_TX_TX_DRV_LVL, - QSERDES_V4_TX_TX_EMP_POST1_LVL); + qmp_combo_configure_dp_swing(qmp); } static int qmp_v456_configure_dp_phy(struct qmp_combo *qmp) @@ -2326,14 +2362,16 @@ static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp) 10000)) return -ETIMEDOUT; - writel(0x0a, qmp->dp_tx + QSERDES_V4_TX_TX_POL_INV); - writel(0x0a, qmp->dp_tx2 + QSERDES_V4_TX_TX_POL_INV); + writel(0x0a, qmp->dp_tx + cfg->regs[QPHY_TX_TX_POL_INV]); + writel(0x0a, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_POL_INV]); - writel(0x27, qmp->dp_tx + QSERDES_V4_TX_TX_DRV_LVL); - writel(0x27, qmp->dp_tx2 + QSERDES_V4_TX_TX_DRV_LVL); + writel(0x27, qmp->dp_tx + cfg->regs[QPHY_TX_TX_DRV_LVL]); + writel(0x27, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_DRV_LVL]); - writel(0x20, qmp->dp_tx + QSERDES_V4_TX_TX_EMP_POST1_LVL); - writel(0x20, qmp->dp_tx2 + QSERDES_V4_TX_TX_EMP_POST1_LVL); + writel(0x20, qmp->dp_tx + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); + writel(0x20, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); + + return 0; return 0; } @@ -2384,14 +2422,14 @@ static int qmp_v5_configure_dp_phy(struct qmp_combo *qmp) 10000)) return -ETIMEDOUT; - writel(0x0a, qmp->dp_tx + QSERDES_V5_5NM_TX_TX_POL_INV); - writel(0x0a, qmp->dp_tx2 + QSERDES_V5_5NM_TX_TX_POL_INV); + writel(0x0a, qmp->dp_tx + cfg->regs[QPHY_TX_TX_POL_INV]); + writel(0x0a, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_POL_INV]); - writel(0x27, qmp->dp_tx + QSERDES_V5_5NM_TX_TX_DRV_LVL); - writel(0x27, qmp->dp_tx2 + QSERDES_V5_5NM_TX_TX_DRV_LVL); + writel(0x27, qmp->dp_tx + cfg->regs[QPHY_TX_TX_DRV_LVL]); + writel(0x27, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_DRV_LVL]); - writel(0x20, qmp->dp_tx + QSERDES_V5_5NM_TX_TX_EMP_POST1_LVL); - writel(0x20, qmp->dp_tx2 + QSERDES_V5_5NM_TX_TX_EMP_POST1_LVL); + writel(0x20, qmp->dp_tx + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); + writel(0x20, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); return 0; } @@ -2442,14 +2480,14 @@ static int qmp_v6_configure_dp_phy(struct qmp_combo *qmp) 10000)) return -ETIMEDOUT; - writel(0x0a, qmp->dp_tx + QSERDES_V4_TX_TX_POL_INV); - writel(0x0a, qmp->dp_tx2 + QSERDES_V4_TX_TX_POL_INV); + writel(0x0a, qmp->dp_tx + cfg->regs[QPHY_TX_TX_POL_INV]); + writel(0x0a, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_POL_INV]); - writel(0x27, qmp->dp_tx + QSERDES_V4_TX_TX_DRV_LVL); - writel(0x27, qmp->dp_tx2 + QSERDES_V4_TX_TX_DRV_LVL); + writel(0x27, qmp->dp_tx + cfg->regs[QPHY_TX_TX_DRV_LVL]); + writel(0x27, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_DRV_LVL]); - writel(0x20, qmp->dp_tx + QSERDES_V4_TX_TX_EMP_POST1_LVL); - writel(0x20, qmp->dp_tx2 + QSERDES_V4_TX_TX_EMP_POST1_LVL); + writel(0x20, qmp->dp_tx + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); + writel(0x20, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); return 0; } diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6.h index a69233e68f9ab..b4810c48dc20a 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6.h @@ -7,6 +7,8 @@ #define QCOM_PHY_QMP_QSERDES_TXRX_USB_V6_H_ #define QSERDES_V6_TX_CLKBUF_ENABLE 0x08 +#define QSERDES_V6_TX_TX_EMP_POST1_LVL 0x0c +#define QSERDES_V6_TX_TX_DRV_LVL 0x14 #define QSERDES_V6_TX_RESET_TSYNC_EN 0x1c #define QSERDES_V6_TX_PRE_STALL_LDO_BOOST_EN 0x20 #define QSERDES_V6_TX_TX_BAND 0x24 @@ -15,6 +17,7 @@ #define QSERDES_V6_TX_RES_CODE_LANE_RX 0x38 #define QSERDES_V6_TX_RES_CODE_LANE_OFFSET_TX 0x3c #define QSERDES_V6_TX_RES_CODE_LANE_OFFSET_RX 0x40 +#define QSERDES_V6_TX_TX_POL_INV 0x5c #define QSERDES_V6_TX_PARRATE_REC_DETECT_IDLE_EN 0x60 #define QSERDES_V6_TX_BIST_PATTERN7 0x7c #define QSERDES_V6_TX_LANE_MODE_1 0x84 diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h index 7ee4b0e07d11b..32d8976847557 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp.h @@ -134,6 +134,8 @@ #define QPHY_V4_PCS_MISC_TYPEC_STATUS 0x10 #define QPHY_V4_PCS_MISC_PLACEHOLDER_STATUS 0x14 +#define QSERDES_V5_DP_PHY_STATUS 0x0dc + /* Only for QMP V6 PHY - DP PHY registers */ #define QSERDES_V6_DP_PHY_AUX_INTERRUPT_STATUS 0x0e0 #define QSERDES_V6_DP_PHY_STATUS 0x0e4 -- GitLab From cd1f3343297ff6129339a011018ea2f68360ba82 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 21 Jun 2023 18:33:14 +0300 Subject: [PATCH 0153/3445] phy: qcom: qmp-combo: reuse register layouts for some more registers Use register layout for TX_HIGHZ_DRVR_EN and TX_TRANSCEIVER_BIAS_EN registers. This will allow us to unify qmp_v[456]_configure_dp_phy() functions in the next commit. Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230621153317.1025914-5-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 34 ++++++++++++------- .../qualcomm/phy-qcom-qmp-qserdes-txrx-v6.h | 2 ++ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index 8dd00a1bb9035..a2db4ce6b7a3e 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -116,6 +116,8 @@ enum qphy_reg_layout { QPHY_TX_TX_POL_INV, QPHY_TX_TX_DRV_LVL, QPHY_TX_TX_EMP_POST1_LVL, + QPHY_TX_HIGHZ_DRVR_EN, + QPHY_TX_TRANSCEIVER_BIAS_EN, /* Keep last to ensure regs_layout arrays are properly initialized */ QPHY_LAYOUT_SIZE @@ -138,6 +140,8 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_TX_TX_POL_INV] = QSERDES_V3_TX_TX_POL_INV, [QPHY_TX_TX_DRV_LVL] = QSERDES_V3_TX_TX_DRV_LVL, [QPHY_TX_TX_EMP_POST1_LVL] = QSERDES_V3_TX_TX_EMP_POST1_LVL, + [QPHY_TX_HIGHZ_DRVR_EN] = QSERDES_V3_TX_HIGHZ_DRVR_EN, + [QPHY_TX_TRANSCEIVER_BIAS_EN] = QSERDES_V3_TX_TRANSCEIVER_BIAS_EN, }; static const unsigned int qmp_v45_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { @@ -159,6 +163,8 @@ static const unsigned int qmp_v45_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_TX_TX_POL_INV] = QSERDES_V4_TX_TX_POL_INV, [QPHY_TX_TX_DRV_LVL] = QSERDES_V4_TX_TX_DRV_LVL, [QPHY_TX_TX_EMP_POST1_LVL] = QSERDES_V4_TX_TX_EMP_POST1_LVL, + [QPHY_TX_HIGHZ_DRVR_EN] = QSERDES_V4_TX_HIGHZ_DRVR_EN, + [QPHY_TX_TRANSCEIVER_BIAS_EN] = QSERDES_V4_TX_TRANSCEIVER_BIAS_EN, }; static const unsigned int qmp_v5_5nm_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { @@ -180,6 +186,8 @@ static const unsigned int qmp_v5_5nm_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_TX_TX_POL_INV] = QSERDES_V5_5NM_TX_TX_POL_INV, [QPHY_TX_TX_DRV_LVL] = QSERDES_V5_5NM_TX_TX_DRV_LVL, [QPHY_TX_TX_EMP_POST1_LVL] = QSERDES_V5_5NM_TX_TX_EMP_POST1_LVL, + [QPHY_TX_HIGHZ_DRVR_EN] = QSERDES_V5_5NM_TX_HIGHZ_DRVR_EN, + [QPHY_TX_TRANSCEIVER_BIAS_EN] = QSERDES_V5_5NM_TX_TRANSCEIVER_BIAS_EN, }; static const unsigned int qmp_v6_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { @@ -201,6 +209,8 @@ static const unsigned int qmp_v6_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_TX_TX_POL_INV] = QSERDES_V6_TX_TX_POL_INV, [QPHY_TX_TX_DRV_LVL] = QSERDES_V6_TX_TX_DRV_LVL, [QPHY_TX_TX_EMP_POST1_LVL] = QSERDES_V6_TX_TX_EMP_POST1_LVL, + [QPHY_TX_HIGHZ_DRVR_EN] = QSERDES_V6_TX_HIGHZ_DRVR_EN, + [QPHY_TX_TRANSCEIVER_BIAS_EN] = QSERDES_V6_TX_TRANSCEIVER_BIAS_EN, }; static const struct qmp_phy_init_tbl qmp_v3_usb3_serdes_tbl[] = { @@ -2346,10 +2356,10 @@ static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp) drvr1_en = 0x10; } - writel(drvr0_en, qmp->dp_tx + QSERDES_V4_TX_HIGHZ_DRVR_EN); - writel(bias0_en, qmp->dp_tx + QSERDES_V4_TX_TRANSCEIVER_BIAS_EN); - writel(drvr1_en, qmp->dp_tx2 + QSERDES_V4_TX_HIGHZ_DRVR_EN); - writel(bias1_en, qmp->dp_tx2 + QSERDES_V4_TX_TRANSCEIVER_BIAS_EN); + writel(drvr0_en, qmp->dp_tx + cfg->regs[QPHY_TX_HIGHZ_DRVR_EN]); + writel(bias0_en, qmp->dp_tx + cfg->regs[QPHY_TX_TRANSCEIVER_BIAS_EN]); + writel(drvr1_en, qmp->dp_tx2 + cfg->regs[QPHY_TX_HIGHZ_DRVR_EN]); + writel(bias1_en, qmp->dp_tx2 + cfg->regs[QPHY_TX_TRANSCEIVER_BIAS_EN]); writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); udelay(2000); @@ -2406,10 +2416,10 @@ static int qmp_v5_configure_dp_phy(struct qmp_combo *qmp) drvr1_en = 0x10; } - writel(drvr0_en, qmp->dp_tx + QSERDES_V5_5NM_TX_HIGHZ_DRVR_EN); - writel(bias0_en, qmp->dp_tx + QSERDES_V5_5NM_TX_TRANSCEIVER_BIAS_EN); - writel(drvr1_en, qmp->dp_tx2 + QSERDES_V5_5NM_TX_HIGHZ_DRVR_EN); - writel(bias1_en, qmp->dp_tx2 + QSERDES_V5_5NM_TX_TRANSCEIVER_BIAS_EN); + writel(drvr0_en, qmp->dp_tx + cfg->regs[QPHY_TX_HIGHZ_DRVR_EN]); + writel(bias0_en, qmp->dp_tx + cfg->regs[QPHY_TX_TRANSCEIVER_BIAS_EN]); + writel(drvr1_en, qmp->dp_tx2 + cfg->regs[QPHY_TX_HIGHZ_DRVR_EN]); + writel(bias1_en, qmp->dp_tx2 + cfg->regs[QPHY_TX_TRANSCEIVER_BIAS_EN]); writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); udelay(2000); @@ -2464,10 +2474,10 @@ static int qmp_v6_configure_dp_phy(struct qmp_combo *qmp) drvr1_en = 0x10; } - writel(drvr0_en, qmp->dp_tx + QSERDES_V4_TX_HIGHZ_DRVR_EN); - writel(bias0_en, qmp->dp_tx + QSERDES_V4_TX_TRANSCEIVER_BIAS_EN); - writel(drvr1_en, qmp->dp_tx2 + QSERDES_V4_TX_HIGHZ_DRVR_EN); - writel(bias1_en, qmp->dp_tx2 + QSERDES_V4_TX_TRANSCEIVER_BIAS_EN); + writel(drvr0_en, qmp->dp_tx + cfg->regs[QPHY_TX_HIGHZ_DRVR_EN]); + writel(bias0_en, qmp->dp_tx + cfg->regs[QPHY_TX_TRANSCEIVER_BIAS_EN]); + writel(drvr1_en, qmp->dp_tx2 + cfg->regs[QPHY_TX_HIGHZ_DRVR_EN]); + writel(bias1_en, qmp->dp_tx2 + cfg->regs[QPHY_TX_TRANSCEIVER_BIAS_EN]); writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); udelay(2000); diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6.h index b4810c48dc20a..8883e1de730ef 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6.h @@ -17,6 +17,8 @@ #define QSERDES_V6_TX_RES_CODE_LANE_RX 0x38 #define QSERDES_V6_TX_RES_CODE_LANE_OFFSET_TX 0x3c #define QSERDES_V6_TX_RES_CODE_LANE_OFFSET_RX 0x40 +#define QSERDES_V6_TX_TRANSCEIVER_BIAS_EN 0x54 +#define QSERDES_V6_TX_HIGHZ_DRVR_EN 0x58 #define QSERDES_V6_TX_TX_POL_INV 0x5c #define QSERDES_V6_TX_PARRATE_REC_DETECT_IDLE_EN 0x60 #define QSERDES_V6_TX_BIST_PATTERN7 0x7c -- GitLab From 9e6a0403f6a14a39581f961220fab77052efc4cf Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 21 Jun 2023 18:33:15 +0300 Subject: [PATCH 0154/3445] phy: qcom: qmp-combo: drop similar functions The functions qmp_v5_configure_dp_phy() and qmp_v6_configure_dp_phy() are now copies of qmp_v4_configure_dp_phy(). Drop them and use the v4 function in all the cases. Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230621153317.1025914-6-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 123 +--------------------- 1 file changed, 2 insertions(+), 121 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index a2db4ce6b7a3e..0b27b3838236c 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -1433,10 +1433,7 @@ static void qmp_v4_configure_dp_tx(struct qmp_combo *qmp); static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp); static int qmp_v4_calibrate_dp_phy(struct qmp_combo *qmp); -static int qmp_v5_configure_dp_phy(struct qmp_combo *qmp); - static void qmp_v6_dp_aux_init(struct qmp_combo *qmp); -static int qmp_v6_configure_dp_phy(struct qmp_combo *qmp); static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val) { @@ -1686,7 +1683,7 @@ static const struct qmp_phy_cfg sc8280xp_usb43dpphy_cfg = { .dp_aux_init = qmp_v4_dp_aux_init, .configure_dp_tx = qmp_v4_configure_dp_tx, - .configure_dp_phy = qmp_v5_configure_dp_phy, + .configure_dp_phy = qmp_v4_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, .clk_list = qmp_v4_phy_clk_l, @@ -1875,7 +1872,7 @@ static const struct qmp_phy_cfg sm8550_usb3dpphy_cfg = { .dp_aux_init = qmp_v6_dp_aux_init, .configure_dp_tx = qmp_v4_configure_dp_tx, - .configure_dp_phy = qmp_v6_configure_dp_phy, + .configure_dp_phy = qmp_v4_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, .regs = qmp_v6_usb3phy_regs_layout, @@ -2386,122 +2383,6 @@ static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp) return 0; } -static int qmp_v5_configure_dp_phy(struct qmp_combo *qmp) -{ - const struct qmp_phy_cfg *cfg = qmp->cfg; - bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE); - const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; - u32 bias0_en, drvr0_en, bias1_en, drvr1_en; - u32 status; - int ret; - - ret = qmp_v456_configure_dp_phy(qmp); - if (ret < 0) - return ret; - - if (dp_opts->lanes == 1) { - bias0_en = reverse ? 0x3e : 0x15; - drvr0_en = reverse ? 0x13 : 0x10; - bias1_en = reverse ? 0x15 : 0x3e; - drvr1_en = reverse ? 0x10 : 0x13; - } else if (dp_opts->lanes == 2) { - bias0_en = reverse ? 0x3f : 0x15; - drvr0_en = 0x10; - bias1_en = reverse ? 0x15 : 0x3f; - drvr1_en = 0x10; - } else { - bias0_en = 0x3f; - bias1_en = 0x3f; - drvr0_en = 0x10; - drvr1_en = 0x10; - } - - writel(drvr0_en, qmp->dp_tx + cfg->regs[QPHY_TX_HIGHZ_DRVR_EN]); - writel(bias0_en, qmp->dp_tx + cfg->regs[QPHY_TX_TRANSCEIVER_BIAS_EN]); - writel(drvr1_en, qmp->dp_tx2 + cfg->regs[QPHY_TX_HIGHZ_DRVR_EN]); - writel(bias1_en, qmp->dp_tx2 + cfg->regs[QPHY_TX_TRANSCEIVER_BIAS_EN]); - - writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); - udelay(2000); - writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); - - if (readl_poll_timeout(qmp->dp_dp_phy + cfg->regs[QPHY_DP_PHY_STATUS], - status, - ((status & BIT(1)) > 0), - 500, - 10000)) - return -ETIMEDOUT; - - writel(0x0a, qmp->dp_tx + cfg->regs[QPHY_TX_TX_POL_INV]); - writel(0x0a, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_POL_INV]); - - writel(0x27, qmp->dp_tx + cfg->regs[QPHY_TX_TX_DRV_LVL]); - writel(0x27, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_DRV_LVL]); - - writel(0x20, qmp->dp_tx + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); - writel(0x20, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); - - return 0; -} - -static int qmp_v6_configure_dp_phy(struct qmp_combo *qmp) -{ - const struct qmp_phy_cfg *cfg = qmp->cfg; - bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE); - const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; - u32 bias0_en, drvr0_en, bias1_en, drvr1_en; - u32 status; - int ret; - - ret = qmp_v456_configure_dp_phy(qmp); - if (ret < 0) - return ret; - - if (dp_opts->lanes == 1) { - bias0_en = reverse ? 0x3e : 0x15; - drvr0_en = reverse ? 0x13 : 0x10; - bias1_en = reverse ? 0x15 : 0x3e; - drvr1_en = reverse ? 0x10 : 0x13; - } else if (dp_opts->lanes == 2) { - bias0_en = reverse ? 0x3f : 0x15; - drvr0_en = 0x10; - bias1_en = reverse ? 0x15 : 0x3f; - drvr1_en = 0x10; - } else { - bias0_en = 0x3f; - bias1_en = 0x3f; - drvr0_en = 0x10; - drvr1_en = 0x10; - } - - writel(drvr0_en, qmp->dp_tx + cfg->regs[QPHY_TX_HIGHZ_DRVR_EN]); - writel(bias0_en, qmp->dp_tx + cfg->regs[QPHY_TX_TRANSCEIVER_BIAS_EN]); - writel(drvr1_en, qmp->dp_tx2 + cfg->regs[QPHY_TX_HIGHZ_DRVR_EN]); - writel(bias1_en, qmp->dp_tx2 + cfg->regs[QPHY_TX_TRANSCEIVER_BIAS_EN]); - - writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); - udelay(2000); - writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); - - if (readl_poll_timeout(qmp->dp_dp_phy + cfg->regs[QPHY_DP_PHY_STATUS], - status, - ((status & BIT(1)) > 0), - 500, - 10000)) - return -ETIMEDOUT; - - writel(0x0a, qmp->dp_tx + cfg->regs[QPHY_TX_TX_POL_INV]); - writel(0x0a, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_POL_INV]); - - writel(0x27, qmp->dp_tx + cfg->regs[QPHY_TX_TX_DRV_LVL]); - writel(0x27, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_DRV_LVL]); - - writel(0x20, qmp->dp_tx + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); - writel(0x20, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); - - return 0; -} - /* * We need to calibrate the aux setting here as many times * as the caller tries -- GitLab From 31a4ac68632024d4d3d27c634f63fe1515833041 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 21 Jun 2023 18:33:16 +0300 Subject: [PATCH 0155/3445] phy: qcom: qmp-combo: drop qmp_v6_dp_aux_init() The only difference between qmp_v6_dp_aux_init() and qmp_v4_dp_aux_init() is the address of COM_BIAS_EN_CLKBUFLR_EN register. Move it to register layout and drop the duplicate function. Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230621153317.1025914-7-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 44 +++++++---------------- 1 file changed, 12 insertions(+), 32 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index 0b27b3838236c..61a1f7c52456b 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -110,6 +110,7 @@ enum qphy_reg_layout { QPHY_COM_RESETSM_CNTRL, QPHY_COM_C_READY_STATUS, QPHY_COM_CMN_STATUS, + QPHY_COM_BIAS_EN_CLKBUFLR_EN, QPHY_DP_PHY_STATUS, @@ -134,6 +135,7 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_COM_RESETSM_CNTRL] = QSERDES_V3_COM_RESETSM_CNTRL, [QPHY_COM_C_READY_STATUS] = QSERDES_V3_COM_C_READY_STATUS, [QPHY_COM_CMN_STATUS] = QSERDES_V3_COM_CMN_STATUS, + [QPHY_COM_BIAS_EN_CLKBUFLR_EN] = QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, [QPHY_DP_PHY_STATUS] = QSERDES_V3_DP_PHY_STATUS, @@ -157,6 +159,7 @@ static const unsigned int qmp_v45_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_COM_RESETSM_CNTRL] = QSERDES_V4_COM_RESETSM_CNTRL, [QPHY_COM_C_READY_STATUS] = QSERDES_V4_COM_C_READY_STATUS, [QPHY_COM_CMN_STATUS] = QSERDES_V4_COM_CMN_STATUS, + [QPHY_COM_BIAS_EN_CLKBUFLR_EN] = QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN, [QPHY_DP_PHY_STATUS] = QSERDES_V4_DP_PHY_STATUS, @@ -180,6 +183,7 @@ static const unsigned int qmp_v5_5nm_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_COM_RESETSM_CNTRL] = QSERDES_V5_COM_RESETSM_CNTRL, [QPHY_COM_C_READY_STATUS] = QSERDES_V5_COM_C_READY_STATUS, [QPHY_COM_CMN_STATUS] = QSERDES_V5_COM_CMN_STATUS, + [QPHY_COM_BIAS_EN_CLKBUFLR_EN] = QSERDES_V5_COM_BIAS_EN_CLKBUFLR_EN, [QPHY_DP_PHY_STATUS] = QSERDES_V5_DP_PHY_STATUS, @@ -203,6 +207,7 @@ static const unsigned int qmp_v6_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_COM_RESETSM_CNTRL] = QSERDES_V6_COM_RESETSM_CNTRL, [QPHY_COM_C_READY_STATUS] = QSERDES_V6_COM_C_READY_STATUS, [QPHY_COM_CMN_STATUS] = QSERDES_V6_COM_CMN_STATUS, + [QPHY_COM_BIAS_EN_CLKBUFLR_EN] = QSERDES_V6_COM_PLL_BIAS_EN_CLK_BUFLR_EN, [QPHY_DP_PHY_STATUS] = QSERDES_V6_DP_PHY_STATUS, @@ -1433,8 +1438,6 @@ static void qmp_v4_configure_dp_tx(struct qmp_combo *qmp); static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp); static int qmp_v4_calibrate_dp_phy(struct qmp_combo *qmp); -static void qmp_v6_dp_aux_init(struct qmp_combo *qmp); - static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val) { u32 reg; @@ -1870,7 +1873,7 @@ static const struct qmp_phy_cfg sm8550_usb3dpphy_cfg = { .swing_hbr3_hbr2 = &qmp_dp_v5_voltage_swing_hbr3_hbr2, .pre_emphasis_hbr3_hbr2 = &qmp_dp_v5_pre_emphasis_hbr3_hbr2, - .dp_aux_init = qmp_v6_dp_aux_init, + .dp_aux_init = qmp_v4_dp_aux_init, .configure_dp_tx = qmp_v4_configure_dp_tx, .configure_dp_phy = qmp_v4_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, @@ -1945,6 +1948,8 @@ static int qmp_combo_dp_serdes_init(struct qmp_combo *qmp) static void qmp_v3_dp_aux_init(struct qmp_combo *qmp) { + const struct qmp_phy_cfg *cfg = qmp->cfg; + writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); @@ -1952,7 +1957,7 @@ static void qmp_v3_dp_aux_init(struct qmp_combo *qmp) /* Turn on BIAS current for PHY/PLL */ writel(QSERDES_V3_COM_BIAS_EN | QSERDES_V3_COM_BIAS_EN_MUX | QSERDES_V3_COM_CLKBUF_L_EN | QSERDES_V3_COM_EN_SYSCLK_TX_SEL, - qmp->dp_serdes + QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN); + qmp->dp_serdes + cfg->regs[QPHY_COM_BIAS_EN_CLKBUFLR_EN]); writel(DP_PHY_PD_CTL_PSR_PWRDN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); @@ -1966,7 +1971,7 @@ static void qmp_v3_dp_aux_init(struct qmp_combo *qmp) QSERDES_V3_COM_BIAS_EN_MUX | QSERDES_V3_COM_CLKBUF_R_EN | QSERDES_V3_COM_CLKBUF_L_EN | QSERDES_V3_COM_EN_SYSCLK_TX_SEL | QSERDES_V3_COM_CLKBUF_RX_DRIVE_L, - qmp->dp_serdes + QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN); + qmp->dp_serdes + cfg->regs[QPHY_COM_BIAS_EN_CLKBUFLR_EN]); writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG0); writel(0x13, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1); @@ -2162,39 +2167,14 @@ static int qmp_v3_calibrate_dp_phy(struct qmp_combo *qmp) static void qmp_v4_dp_aux_init(struct qmp_combo *qmp) { - writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_PSR_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | - DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, - qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); - - /* Turn on BIAS current for PHY/PLL */ - writel(0x17, qmp->dp_serdes + QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN); - - writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG0); - writel(0x13, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1); - writel(0xa4, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG2); - writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG3); - writel(0x0a, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG4); - writel(0x26, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG5); - writel(0x0a, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG6); - writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG7); - writel(0xb7, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG8); - writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG9); - qmp->dp_aux_cfg = 0; - - writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK | - PHY_AUX_SYNC_ERR_MASK | PHY_AUX_ALIGN_ERR_MASK | - PHY_AUX_REQ_ERR_MASK, - qmp->dp_dp_phy + QSERDES_V4_DP_PHY_AUX_INTERRUPT_MASK); -} + const struct qmp_phy_cfg *cfg = qmp->cfg; -static void qmp_v6_dp_aux_init(struct qmp_combo *qmp) -{ writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_PSR_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); /* Turn on BIAS current for PHY/PLL */ - writel(0x17, qmp->dp_serdes + QSERDES_V6_COM_PLL_BIAS_EN_CLK_BUFLR_EN); + writel(0x17, qmp->dp_serdes + cfg->regs[QPHY_COM_BIAS_EN_CLKBUFLR_EN]); writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG0); writel(0x13, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1); -- GitLab From ec17373aebd03b36b5f9a6bd4266c1cfd1001e1d Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 21 Jun 2023 18:33:17 +0300 Subject: [PATCH 0156/3445] phy: qcom: qmp-combo: extract common function to setup clocks Extact qmp_combo_configure_dp_clocks(), a common function to setup PHY clocks depending on the selected link rate. Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230621153317.1025914-8-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 63 ++++++++++------------- 1 file changed, 26 insertions(+), 37 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index 61a1f7c52456b..36eb516f91703 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -2074,18 +2074,12 @@ static bool qmp_combo_configure_dp_mode(struct qmp_combo *qmp) return reverse; } -static int qmp_v3_configure_dp_phy(struct qmp_combo *qmp) +static int qmp_combo_configure_dp_clocks(struct qmp_combo *qmp) { const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; - const struct qmp_phy_cfg *cfg = qmp->cfg; - u32 phy_vco_div, status; + u32 phy_vco_div; unsigned long pixel_freq; - qmp_combo_configure_dp_mode(qmp); - - writel(0x05, qmp->dp_dp_phy + QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL); - writel(0x05, qmp->dp_dp_phy + QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL); - switch (dp_opts->link_rate) { case 1620: phy_vco_div = 0x1; @@ -2107,11 +2101,29 @@ static int qmp_v3_configure_dp_phy(struct qmp_combo *qmp) /* Other link rates aren't supported */ return -EINVAL; } - writel(phy_vco_div, qmp->dp_dp_phy + QSERDES_V3_DP_PHY_VCO_DIV); + writel(phy_vco_div, qmp->dp_dp_phy + QSERDES_V4_DP_PHY_VCO_DIV); clk_set_rate(qmp->dp_link_hw.clk, dp_opts->link_rate * 100000); clk_set_rate(qmp->dp_pixel_hw.clk, pixel_freq); + return 0; +} + +static int qmp_v3_configure_dp_phy(struct qmp_combo *qmp) +{ + const struct qmp_phy_cfg *cfg = qmp->cfg; + u32 status; + int ret; + + qmp_combo_configure_dp_mode(qmp); + + writel(0x05, qmp->dp_dp_phy + QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL); + writel(0x05, qmp->dp_dp_phy + QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL); + + ret = qmp_combo_configure_dp_clocks(qmp); + if (ret) + return ret; + writel(0x04, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG2); writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); writel(0x05, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); @@ -2210,10 +2222,9 @@ static void qmp_v4_configure_dp_tx(struct qmp_combo *qmp) static int qmp_v456_configure_dp_phy(struct qmp_combo *qmp) { - const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; const struct qmp_phy_cfg *cfg = qmp->cfg; - u32 phy_vco_div, status; - unsigned long pixel_freq; + u32 status; + int ret; writel(0x0f, qmp->dp_dp_phy + QSERDES_V4_DP_PHY_CFG_1); @@ -2225,31 +2236,9 @@ static int qmp_v456_configure_dp_phy(struct qmp_combo *qmp) writel(0x05, qmp->dp_dp_phy + QSERDES_V4_DP_PHY_TX0_TX1_LANE_CTL); writel(0x05, qmp->dp_dp_phy + QSERDES_V4_DP_PHY_TX2_TX3_LANE_CTL); - switch (dp_opts->link_rate) { - case 1620: - phy_vco_div = 0x1; - pixel_freq = 1620000000UL / 2; - break; - case 2700: - phy_vco_div = 0x1; - pixel_freq = 2700000000UL / 2; - break; - case 5400: - phy_vco_div = 0x2; - pixel_freq = 5400000000UL / 4; - break; - case 8100: - phy_vco_div = 0x0; - pixel_freq = 8100000000UL / 6; - break; - default: - /* Other link rates aren't supported */ - return -EINVAL; - } - writel(phy_vco_div, qmp->dp_dp_phy + QSERDES_V4_DP_PHY_VCO_DIV); - - clk_set_rate(qmp->dp_link_hw.clk, dp_opts->link_rate * 100000); - clk_set_rate(qmp->dp_pixel_hw.clk, pixel_freq); + ret = qmp_combo_configure_dp_clocks(qmp); + if (ret) + return ret; writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); writel(0x05, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); -- GitLab From 644c06dfbd0da713f772abf0a8f8581ac78e6264 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Thu, 15 Jun 2023 17:10:17 +0000 Subject: [PATCH 0157/3445] phy/rockchip: inno-hdmi: use correct vco_div_5 macro on rk3328 inno_hdmi_phy_rk3328_clk_set_rate() is using the RK3228 macro when configuring vco_div_5 on RK3328. Fix this by using correct vco_div_5 macro for RK3328. Fixes: 53706a116863 ("phy: add Rockchip Innosilicon hdmi phy") Signed-off-by: Jonas Karlman Link: https://lore.kernel.org/r/20230615171005.2251032-2-jonas@kwiboo.se Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c index 1e1563f5fffc4..f348e5347d817 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c @@ -790,8 +790,8 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw, RK3328_PRE_PLL_POWER_DOWN); /* Configure pre-pll */ - inno_update_bits(inno, 0xa0, RK3228_PCLK_VCO_DIV_5_MASK, - RK3228_PCLK_VCO_DIV_5(cfg->vco_div_5_en)); + inno_update_bits(inno, 0xa0, RK3328_PCLK_VCO_DIV_5_MASK, + RK3328_PCLK_VCO_DIV_5(cfg->vco_div_5_en)); inno_write(inno, 0xa1, RK3328_PRE_PLL_PRE_DIV(cfg->prediv)); val = RK3328_SPREAD_SPECTRUM_MOD_DISABLE; -- GitLab From d5ef343c1d62bc4c4c2c393af654a41cb34b449f Mon Sep 17 00:00:00 2001 From: Zheng Yang Date: Thu, 15 Jun 2023 17:10:19 +0000 Subject: [PATCH 0158/3445] phy/rockchip: inno-hdmi: round fractal pixclock in rk3328 recalc_rate inno_hdmi_phy_rk3328_clk_recalc_rate() is returning a rate not found in the pre pll config table when the fractal divider is used. This can prevent proper power_on because a tmdsclock for the new rate is not found in the pre pll config table. Fix this by saving and returning a rounded pixel rate that exist in the pre pll config table. Fixes: 53706a116863 ("phy: add Rockchip Innosilicon hdmi phy") Signed-off-by: Zheng Yang Signed-off-by: Jonas Karlman Link: https://lore.kernel.org/r/20230615171005.2251032-3-jonas@kwiboo.se Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c index f348e5347d817..7d412f771f6c3 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c @@ -745,10 +745,12 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw, do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2)); } - inno->pixclock = vco; - dev_dbg(inno->dev, "%s rate %lu\n", __func__, inno->pixclock); + inno->pixclock = DIV_ROUND_CLOSEST((unsigned long)vco, 1000) * 1000; - return vco; + dev_dbg(inno->dev, "%s rate %lu vco %llu\n", + __func__, inno->pixclock, vco); + + return inno->pixclock; } static long inno_hdmi_phy_rk3328_clk_round_rate(struct clk_hw *hw, -- GitLab From b001c27d772e35a3b6736d9ac34e2e1019b1a782 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Thu, 15 Jun 2023 17:10:20 +0000 Subject: [PATCH 0159/3445] phy/rockchip: inno-hdmi: remove unused no_c from rk3328 recalc_rate no_c is not used in any calculation, lets remove it. Signed-off-by: Jonas Karlman Link: https://lore.kernel.org/r/20230615171005.2251032-4-jonas@kwiboo.se Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c index 7d412f771f6c3..f027e0a2e26ba 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c @@ -714,7 +714,7 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw, { struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); unsigned long frac; - u8 nd, no_a, no_b, no_c, no_d; + u8 nd, no_a, no_b, no_d; u64 vco; u16 nf; @@ -737,9 +737,6 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw, no_b = inno_read(inno, 0xa5) & RK3328_PRE_PLL_PCLK_DIV_B_MASK; no_b >>= RK3328_PRE_PLL_PCLK_DIV_B_SHIFT; no_b += 2; - no_c = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_C_MASK; - no_c >>= RK3328_PRE_PLL_PCLK_DIV_C_SHIFT; - no_c = 1 << no_c; no_d = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_D_MASK; do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2)); -- GitLab From 19a1d46bd699940a496d3b0d4e142ef99834988c Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Thu, 15 Jun 2023 17:10:21 +0000 Subject: [PATCH 0160/3445] phy/rockchip: inno-hdmi: do not power on rk3328 post pll on reg write inno_write is used to configure 0xaa reg, that also hold the POST_PLL_POWER_DOWN bit. When POST_PLL_REFCLK_SEL_TMDS is configured the power down bit is not taken into consideration. Fix this by keeping the power down bit until configuration is complete. Also reorder the reg write order for consistency. Fixes: 53706a116863 ("phy: add Rockchip Innosilicon hdmi phy") Signed-off-by: Jonas Karlman Link: https://lore.kernel.org/r/20230615171005.2251032-5-jonas@kwiboo.se Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c index f027e0a2e26ba..fe7fa9a43ec0a 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c @@ -1020,9 +1020,10 @@ inno_hdmi_phy_rk3328_power_on(struct inno_hdmi_phy *inno, inno_write(inno, 0xac, RK3328_POST_PLL_FB_DIV_7_0(cfg->fbdiv)); if (cfg->postdiv == 1) { - inno_write(inno, 0xaa, RK3328_POST_PLL_REFCLK_SEL_TMDS); inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) | RK3328_POST_PLL_PRE_DIV(cfg->prediv)); + inno_write(inno, 0xaa, RK3328_POST_PLL_REFCLK_SEL_TMDS | + RK3328_POST_PLL_POWER_DOWN); } else { v = (cfg->postdiv / 2) - 1; v &= RK3328_POST_PLL_POST_DIV_MASK; @@ -1030,7 +1031,8 @@ inno_hdmi_phy_rk3328_power_on(struct inno_hdmi_phy *inno, inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) | RK3328_POST_PLL_PRE_DIV(cfg->prediv)); inno_write(inno, 0xaa, RK3328_POST_PLL_POST_DIV_ENABLE | - RK3328_POST_PLL_REFCLK_SEL_TMDS); + RK3328_POST_PLL_REFCLK_SEL_TMDS | + RK3328_POST_PLL_POWER_DOWN); } for (v = 0; v < 14; v++) -- GitLab From f79b812baf21366fae975b29f671258fb38d643b Mon Sep 17 00:00:00 2001 From: Huicong Xu Date: Thu, 15 Jun 2023 17:10:23 +0000 Subject: [PATCH 0161/3445] phy/rockchip: inno-hdmi: force set_rate on power_on Regular 8-bit and Deep Color video formats mainly differ in TMDS rate and not in pixel clock rate. When the hdmiphy clock is configured with the same pixel clock rate using clk_set_rate() the clock framework do not signal the hdmi phy driver to set_rate when switching between 8-bit and Deep Color. This result in pre/post pll not being re-configured when switching between regular 8-bit and Deep Color video formats. Fix this by calling set_rate in power_on to force pre pll re-configuration. Signed-off-by: Huicong Xu Signed-off-by: Jonas Karlman Link: https://lore.kernel.org/r/20230615171005.2251032-6-jonas@kwiboo.se Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c index fe7fa9a43ec0a..a1fb39af64934 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c @@ -245,6 +245,7 @@ struct inno_hdmi_phy { struct clk_hw hw; struct clk *phyclk; unsigned long pixclock; + unsigned long tmdsclock; }; struct pre_pll_config { @@ -485,6 +486,8 @@ static int inno_hdmi_phy_power_on(struct phy *phy) dev_dbg(inno->dev, "Inno HDMI PHY Power On\n"); + inno->plat_data->clk_ops->set_rate(&inno->hw, inno->pixclock, 24000000); + ret = clk_prepare_enable(inno->phyclk); if (ret) return ret; @@ -509,6 +512,8 @@ static int inno_hdmi_phy_power_off(struct phy *phy) clk_disable_unprepare(inno->phyclk); + inno->tmdsclock = 0; + dev_dbg(inno->dev, "Inno HDMI PHY Power Off\n"); return 0; @@ -628,6 +633,9 @@ static int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw, dev_dbg(inno->dev, "%s rate %lu tmdsclk %lu\n", __func__, rate, tmdsclock); + if (inno->pixclock == rate && inno->tmdsclock == tmdsclock) + return 0; + cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate); if (IS_ERR(cfg)) return PTR_ERR(cfg); @@ -670,6 +678,7 @@ static int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw, } inno->pixclock = rate; + inno->tmdsclock = tmdsclock; return 0; } @@ -781,6 +790,9 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw, dev_dbg(inno->dev, "%s rate %lu tmdsclk %lu\n", __func__, rate, tmdsclock); + if (inno->pixclock == rate && inno->tmdsclock == tmdsclock) + return 0; + cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate); if (IS_ERR(cfg)) return PTR_ERR(cfg); @@ -820,6 +832,7 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw, } inno->pixclock = rate; + inno->tmdsclock = tmdsclock; return 0; } -- GitLab From d1ea4239a10bf32acb321328e074919fa1eb5468 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Thu, 15 Jun 2023 17:10:24 +0000 Subject: [PATCH 0162/3445] phy/rockchip: inno-hdmi: add more supported pre-pll rates This adds a bunch of new pixel clock- and tmds rates to the pre-pll table which are required to get more VESA and some DMT rates working. It has been completely re-calculated to match the min- and max-vco of (750 MHz - 3.2 GHz) requirements. If more than one configuration would have been possible the lowest fbdiv and refdiv (and therefore lowest vco rate) has been preferred. It's important to note, that RK3228 version of the phy does not support fractional dividers. To support the most possible rates for this version also in both 8-bit and 10-bit variant, some rates are not exact. The maximum deviation of the pixel clock is 0.26, which perfectly fits into VESA DMT recommendation of 0.5%. I tested all possible rates on several screens from different manufacturers with both RK3228 and RK3328. Both pre- and post-PLL locking are slighlty faster now. Signed-off-by: Alex Bee Signed-off-by: Jonas Karlman Link: https://lore.kernel.org/r/20230615171005.2251032-7-jonas@kwiboo.se Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 198 +++++++++++++++--- 1 file changed, 173 insertions(+), 25 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c index a1fb39af64934..88ddbfb90eedc 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c @@ -292,31 +292,179 @@ struct inno_hdmi_phy_drv_data { }; static const struct pre_pll_config pre_pll_cfg_table[] = { - { 27000000, 27000000, 1, 90, 3, 2, 2, 10, 3, 3, 4, 0, 0}, - { 27000000, 33750000, 1, 90, 1, 3, 3, 10, 3, 3, 4, 0, 0}, - { 40000000, 40000000, 1, 80, 2, 2, 2, 12, 2, 2, 2, 0, 0}, - { 59341000, 59341000, 1, 98, 3, 1, 2, 1, 3, 3, 4, 0, 0xE6AE6B}, - { 59400000, 59400000, 1, 99, 3, 1, 1, 1, 3, 3, 4, 0, 0}, - { 59341000, 74176250, 1, 98, 0, 3, 3, 1, 3, 3, 4, 0, 0xE6AE6B}, - { 59400000, 74250000, 1, 99, 1, 2, 2, 1, 3, 3, 4, 0, 0}, - { 74176000, 74176000, 1, 98, 1, 2, 2, 1, 2, 3, 4, 0, 0xE6AE6B}, - { 74250000, 74250000, 1, 99, 1, 2, 2, 1, 2, 3, 4, 0, 0}, - { 74176000, 92720000, 4, 494, 1, 2, 2, 1, 3, 3, 4, 0, 0x816817}, - { 74250000, 92812500, 4, 495, 1, 2, 2, 1, 3, 3, 4, 0, 0}, - {148352000, 148352000, 1, 98, 1, 1, 1, 1, 2, 2, 2, 0, 0xE6AE6B}, - {148500000, 148500000, 1, 99, 1, 1, 1, 1, 2, 2, 2, 0, 0}, - {148352000, 185440000, 4, 494, 0, 2, 2, 1, 3, 2, 2, 0, 0x816817}, - {148500000, 185625000, 4, 495, 0, 2, 2, 1, 3, 2, 2, 0, 0}, - {296703000, 296703000, 1, 98, 0, 1, 1, 1, 0, 2, 2, 0, 0xE6AE6B}, - {297000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 2, 0, 0}, - {296703000, 370878750, 4, 494, 1, 2, 0, 1, 3, 1, 1, 0, 0x816817}, - {297000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 0, 0}, - {593407000, 296703500, 1, 98, 0, 1, 1, 1, 0, 2, 1, 0, 0xE6AE6B}, - {594000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 1, 0, 0}, - {593407000, 370879375, 4, 494, 1, 2, 0, 1, 3, 1, 1, 1, 0x816817}, - {594000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 1, 0}, - {593407000, 593407000, 1, 98, 0, 2, 0, 1, 0, 1, 1, 0, 0xE6AE6B}, - {594000000, 594000000, 1, 99, 0, 2, 0, 1, 0, 1, 1, 0, 0}, + { 25175000, 25175000, 3, 125, 3, 1, 1, 1, 3, 3, 4, 0, 0xe00000}, + { 25175000, 31468750, 1, 41, 0, 3, 3, 1, 3, 3, 4, 0, 0xf5554f}, + { 27000000, 27000000, 1, 36, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, + { 27000000, 33750000, 1, 45, 0, 3, 3, 1, 3, 3, 4, 0, 0x0}, + { 31500000, 31500000, 1, 42, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, + { 31500000, 39375000, 1, 105, 1, 3, 3, 10, 0, 3, 4, 0, 0x0}, + { 33750000, 33750000, 1, 45, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, + { 33750000, 42187500, 1, 169, 2, 3, 3, 15, 0, 3, 4, 0, 0x0}, + { 35500000, 35500000, 1, 71, 2, 2, 2, 6, 0, 3, 4, 0, 0x0}, + { 35500000, 44375000, 1, 74, 3, 1, 1, 25, 0, 1, 1, 0, 0x0}, + { 36000000, 36000000, 1, 36, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, + { 36000000, 45000000, 1, 45, 2, 1, 1, 15, 0, 1, 1, 0, 0x0}, + { 40000000, 40000000, 1, 40, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, + { 40000000, 50000000, 1, 50, 2, 1, 1, 15, 0, 1, 1, 0, 0x0}, + { 49500000, 49500000, 1, 66, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, + { 49500000, 61875000, 1, 165, 1, 3, 3, 10, 0, 3, 4, 0, 0x0}, + { 50000000, 50000000, 1, 50, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, + { 50000000, 62500000, 1, 125, 2, 2, 2, 15, 0, 2, 2, 0, 0x0}, + { 54000000, 54000000, 1, 36, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, + { 54000000, 67500000, 1, 45, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, + { 56250000, 56250000, 1, 75, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, + { 56250000, 70312500, 1, 117, 3, 1, 1, 25, 0, 1, 1, 0, 0x0}, + { 59341000, 59341000, 1, 118, 2, 2, 2, 6, 0, 3, 4, 0, 0xae978d}, + { 59341000, 74176250, 2, 148, 2, 1, 1, 15, 0, 1, 1, 0, 0x5a3d70}, + { 59400000, 59400000, 1, 99, 3, 1, 1, 1, 3, 3, 4, 0, 0x0}, + { 59400000, 74250000, 1, 99, 0, 3, 3, 1, 3, 3, 4, 0, 0x0}, + { 65000000, 65000000, 1, 65, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, + { 65000000, 81250000, 3, 325, 0, 3, 3, 1, 3, 3, 4, 0, 0x0}, + { 68250000, 68250000, 1, 91, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, + { 68250000, 85312500, 1, 142, 3, 1, 1, 25, 0, 1, 1, 0, 0x0}, + { 71000000, 71000000, 1, 71, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, + { 71000000, 88750000, 3, 355, 0, 3, 3, 1, 3, 3, 4, 0, 0x0}, + { 72000000, 72000000, 1, 36, 2, 0, 0, 1, 1, 2, 2, 0, 0x0}, + { 72000000, 90000000, 1, 60, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, + { 73250000, 73250000, 3, 293, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, + { 73250000, 91562500, 1, 61, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, + { 74176000, 74176000, 1, 37, 2, 0, 0, 1, 1, 2, 2, 0, 0x16872b}, + { 74176000, 92720000, 2, 185, 2, 1, 1, 15, 0, 1, 1, 0, 0x70a3d7}, + { 74250000, 74250000, 1, 99, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, + { 74250000, 92812500, 4, 495, 0, 3, 3, 1, 3, 3, 4, 0, 0x0}, + { 75000000, 75000000, 1, 50, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, + { 75000000, 93750000, 1, 125, 0, 3, 3, 1, 3, 3, 4, 0, 0x0}, + { 78750000, 78750000, 1, 105, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, + { 78750000, 98437500, 1, 164, 3, 1, 1, 25, 0, 1, 1, 0, 0x0}, + { 79500000, 79500000, 1, 53, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, + { 79500000, 99375000, 1, 199, 2, 2, 2, 15, 0, 2, 2, 0, 0x0}, + { 83500000, 83500000, 2, 167, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, + { 83500000, 104375000, 1, 104, 2, 1, 1, 15, 0, 1, 1, 0, 0x600000}, + { 85500000, 85500000, 1, 57, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, + { 85500000, 106875000, 1, 178, 3, 1, 1, 25, 0, 1, 1, 0, 0x0}, + { 85750000, 85750000, 3, 343, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, + { 85750000, 107187500, 1, 143, 0, 3, 3, 1, 3, 3, 4, 0, 0x0}, + { 88750000, 88750000, 3, 355, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, + { 88750000, 110937500, 1, 110, 2, 1, 1, 15, 0, 1, 1, 0, 0xf00000}, + { 94500000, 94500000, 1, 63, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, + { 94500000, 118125000, 1, 197, 3, 1, 1, 25, 0, 1, 1, 0, 0x0}, + {101000000, 101000000, 1, 101, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, + {101000000, 126250000, 1, 42, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, + {102250000, 102250000, 4, 409, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, + {102250000, 127812500, 1, 128, 2, 1, 1, 15, 0, 1, 1, 0, 0x0}, + {106500000, 106500000, 1, 71, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, + {106500000, 133125000, 1, 133, 2, 1, 1, 15, 0, 1, 1, 0, 0x0}, + {108000000, 108000000, 1, 36, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, + {108000000, 135000000, 1, 45, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, + {115500000, 115500000, 1, 77, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, + {115500000, 144375000, 1, 48, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, + {117500000, 117500000, 2, 235, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, + {117500000, 146875000, 1, 49, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, + {119000000, 119000000, 1, 119, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, + {119000000, 148750000, 3, 148, 0, 1, 1, 1, 3, 1, 1, 0, 0xc00000}, + {121750000, 121750000, 4, 487, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, + {121750000, 152187500, 1, 203, 0, 3, 3, 1, 3, 3, 4, 0, 0x0}, + {122500000, 122500000, 2, 245, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, + {122500000, 153125000, 1, 51, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, + {135000000, 135000000, 1, 45, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, + {135000000, 168750000, 1, 169, 2, 1, 1, 15, 0, 1, 1, 0, 0x0}, + {136750000, 136750000, 1, 68, 2, 0, 0, 1, 1, 2, 2, 0, 0x600000}, + {136750000, 170937500, 1, 113, 0, 2, 2, 1, 3, 2, 2, 0, 0xf5554f}, + {140250000, 140250000, 2, 187, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, + {140250000, 175312500, 1, 117, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, + {146250000, 146250000, 2, 195, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, + {146250000, 182812500, 1, 61, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, + {148250000, 148250000, 3, 222, 2, 0, 0, 1, 1, 2, 2, 0, 0x600000}, + {148250000, 185312500, 1, 123, 0, 2, 2, 1, 3, 2, 2, 0, 0x8aaab0}, + {148352000, 148352000, 2, 148, 2, 0, 0, 1, 1, 2, 2, 0, 0x5a1cac}, + {148352000, 185440000, 3, 185, 0, 1, 1, 1, 3, 1, 1, 0, 0x70a3d7}, + {148500000, 148500000, 1, 99, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, + {148500000, 185625000, 4, 495, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, + {154000000, 154000000, 1, 77, 2, 0, 0, 1, 1, 2, 2, 0, 0x0}, + {154000000, 192500000, 1, 64, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, + {156000000, 156000000, 1, 52, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, + {156000000, 195000000, 1, 65, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, + {156750000, 156750000, 2, 209, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, + {156750000, 195937500, 1, 196, 2, 1, 1, 15, 0, 1, 1, 0, 0x0}, + {157000000, 157000000, 2, 157, 2, 0, 0, 1, 1, 2, 2, 0, 0x0}, + {157000000, 196250000, 1, 131, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, + {157500000, 157500000, 1, 105, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, + {157500000, 196875000, 1, 197, 2, 1, 1, 15, 0, 1, 1, 0, 0x0}, + {162000000, 162000000, 1, 54, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, + {162000000, 202500000, 2, 135, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, + {175500000, 175500000, 1, 117, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, + {175500000, 219375000, 1, 73, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, + {179500000, 179500000, 3, 359, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, + {179500000, 224375000, 1, 75, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, + {182750000, 182750000, 1, 91, 2, 0, 0, 1, 1, 2, 2, 0, 0x600000}, + {182750000, 228437500, 1, 152, 0, 2, 2, 1, 3, 2, 2, 0, 0x4aaab0}, + {182750000, 228437500, 1, 152, 0, 2, 2, 1, 3, 2, 2, 0, 0x4aaab0}, + {187000000, 187000000, 2, 187, 2, 0, 0, 1, 1, 2, 2, 0, 0x0}, + {187000000, 233750000, 1, 39, 0, 0, 0, 1, 3, 0, 0, 1, 0x0}, + {187250000, 187250000, 3, 280, 2, 0, 0, 1, 1, 2, 2, 0, 0xe00000}, + {187250000, 234062500, 1, 156, 0, 2, 2, 1, 3, 2, 2, 0, 0xaaab0}, + {189000000, 189000000, 1, 63, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, + {189000000, 236250000, 1, 79, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, + {193250000, 193250000, 3, 289, 2, 0, 0, 1, 1, 2, 2, 0, 0xe00000}, + {193250000, 241562500, 1, 161, 0, 2, 2, 1, 3, 2, 2, 0, 0xaaab0}, + {202500000, 202500000, 2, 135, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, + {202500000, 253125000, 1, 169, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, + {204750000, 204750000, 4, 273, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, + {204750000, 255937500, 1, 171, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, + {208000000, 208000000, 1, 104, 2, 0, 0, 1, 1, 2, 2, 0, 0x0}, + {208000000, 260000000, 1, 173, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, + {214750000, 214750000, 1, 107, 2, 0, 0, 1, 1, 2, 2, 0, 0x600000}, + {214750000, 268437500, 1, 178, 0, 2, 2, 1, 3, 2, 2, 0, 0xf5554f}, + {218250000, 218250000, 4, 291, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, + {218250000, 272812500, 1, 91, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, + {229500000, 229500000, 2, 153, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, + {229500000, 286875000, 1, 191, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, + {234000000, 234000000, 1, 39, 0, 0, 0, 1, 0, 1, 1, 0, 0x0}, + {234000000, 292500000, 1, 195, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, + {241500000, 241500000, 2, 161, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, + {241500000, 301875000, 1, 201, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, + {245250000, 245250000, 4, 327, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, + {245250000, 306562500, 1, 51, 0, 0, 0, 1, 3, 0, 0, 1, 0x0}, + {245500000, 245500000, 4, 491, 2, 0, 0, 1, 1, 2, 2, 0, 0x0}, + {245500000, 306875000, 1, 51, 0, 0, 0, 1, 3, 0, 0, 1, 0x0}, + {261000000, 261000000, 1, 87, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, + {261000000, 326250000, 1, 109, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, + {268250000, 268250000, 9, 402, 0, 0, 0, 1, 0, 1, 1, 0, 0x600000}, + {268250000, 335312500, 1, 111, 0, 1, 1, 1, 3, 1, 1, 0, 0xc5554f}, + {268500000, 268500000, 2, 179, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, + {268500000, 335625000, 1, 56, 0, 0, 0, 1, 3, 0, 0, 1, 0x0}, + {281250000, 281250000, 4, 375, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, + {281250000, 351562500, 1, 117, 0, 3, 1, 1, 3, 1, 1, 0, 0x0}, + {288000000, 288000000, 1, 48, 0, 0, 0, 1, 0, 1, 1, 0, 0x0}, + {288000000, 360000000, 1, 60, 0, 2, 0, 1, 3, 0, 0, 1, 0x0}, + {296703000, 296703000, 1, 49, 0, 0, 0, 1, 0, 1, 1, 0, 0x7353f7}, + {296703000, 370878750, 1, 123, 0, 3, 1, 1, 3, 1, 1, 0, 0xa051eb}, + {297000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, + {297000000, 371250000, 4, 495, 0, 3, 1, 1, 3, 1, 1, 0, 0x0}, + {312250000, 312250000, 9, 468, 0, 0, 0, 1, 0, 1, 1, 0, 0x600000}, + {312250000, 390312500, 1, 130, 0, 3, 1, 1, 3, 1, 1, 0, 0x1aaab0}, + {317000000, 317000000, 3, 317, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, + {317000000, 396250000, 1, 66, 0, 2, 0, 1, 3, 0, 0, 1, 0x0}, + {319750000, 319750000, 3, 159, 0, 0, 0, 1, 0, 1, 1, 0, 0xe00000}, + {319750000, 399687500, 3, 199, 0, 2, 0, 1, 3, 0, 0, 1, 0xd80000}, + {333250000, 333250000, 9, 499, 0, 0, 0, 1, 0, 1, 1, 0, 0xe00000}, + {333250000, 416562500, 1, 138, 0, 3, 1, 1, 3, 1, 1, 0, 0xdaaab0}, + {348500000, 348500000, 9, 522, 0, 2, 0, 1, 0, 1, 1, 0, 0xc00000}, + {348500000, 435625000, 1, 145, 0, 3, 1, 1, 3, 1, 1, 0, 0x35554f}, + {356500000, 356500000, 9, 534, 0, 2, 0, 1, 0, 1, 1, 0, 0xc00000}, + {356500000, 445625000, 1, 148, 0, 3, 1, 1, 3, 1, 1, 0, 0x8aaab0}, + {380500000, 380500000, 9, 570, 0, 2, 0, 1, 0, 1, 1, 0, 0xc00000}, + {380500000, 475625000, 1, 158, 0, 3, 1, 1, 3, 1, 1, 0, 0x8aaab0}, + {443250000, 443250000, 1, 73, 0, 2, 0, 1, 0, 1, 1, 0, 0xe00000}, + {443250000, 554062500, 1, 92, 0, 2, 0, 1, 3, 0, 0, 1, 0x580000}, + {505250000, 505250000, 9, 757, 0, 2, 0, 1, 0, 1, 1, 0, 0xe00000}, + {552750000, 552750000, 3, 276, 0, 2, 0, 1, 0, 1, 1, 0, 0x600000}, + {593407000, 296703500, 3, 296, 0, 1, 1, 1, 0, 1, 1, 0, 0xb41893}, + {593407000, 370879375, 4, 494, 0, 3, 1, 1, 3, 0, 0, 1, 0x817e4a}, + {593407000, 593407000, 3, 296, 0, 2, 0, 1, 0, 1, 1, 0, 0xb41893}, + {594000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 1, 1, 0, 0x0}, + {594000000, 371250000, 4, 495, 0, 3, 1, 1, 3, 0, 0, 1, 0x0}, + {594000000, 594000000, 1, 99, 0, 2, 0, 1, 0, 1, 1, 0, 0x0}, { /* sentinel */ } }; -- GitLab From a1d12987c38fd97b5e9f266dc849c2d2c6a5bd54 Mon Sep 17 00:00:00 2001 From: Marcin Wierzbicki Date: Mon, 26 Jun 2023 10:55:32 +0000 Subject: [PATCH 0163/3445] phy: cadence: Sierra: Add single link SGMII register configuration Add single link SGMII register configuration for no SSC for cdns,sierra-phy-t0 compatibility string. The configuration is based on Sierra Programmer's Guide and validated in Cisco CrayAR SoC. Co-developed-by: Bartosz Wawrzyniak Signed-off-by: Bartosz Wawrzyniak Signed-off-by: Marcin Wierzbicki Link: https://lore.kernel.org/r/20230626105533.2999966-1-mawierzb@cisco.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-sierra.c | 98 ++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c index 7df9c79a772aa..d4eb93ce82323 100644 --- a/drivers/phy/cadence/phy-cadence-sierra.c +++ b/drivers/phy/cadence/phy-cadence-sierra.c @@ -30,23 +30,34 @@ #define SIERRA_COMMON_CDB_OFFSET 0x0 #define SIERRA_MACRO_ID_REG 0x0 #define SIERRA_CMN_PLLLC_GEN_PREG 0x42 +#define SIERRA_CMN_PLLLC_FBDIV_INT_MODE0_PREG 0x43 +#define SIERRA_CMN_PLLLC_DCOCAL_CTRL_PREG 0x45 +#define SIERRA_CMN_PLLLC_INIT_PREG 0x46 +#define SIERRA_CMN_PLLLC_ITERTMR_PREG 0x47 #define SIERRA_CMN_PLLLC_MODE_PREG 0x48 #define SIERRA_CMN_PLLLC_LF_COEFF_MODE1_PREG 0x49 #define SIERRA_CMN_PLLLC_LF_COEFF_MODE0_PREG 0x4A #define SIERRA_CMN_PLLLC_LOCK_CNTSTART_PREG 0x4B +#define SIERRA_CMN_PLLLC_LOCKSEARCH_PREG 0x4C #define SIERRA_CMN_PLLLC_CLK1_PREG 0x4D +#define SIERRA_CMN_PLLLC_CLK0_PREG 0x4E #define SIERRA_CMN_PLLLC_BWCAL_MODE1_PREG 0x4F #define SIERRA_CMN_PLLLC_BWCAL_MODE0_PREG 0x50 #define SIERRA_CMN_PLLLC_DSMCORR_PREG 0x51 #define SIERRA_CMN_PLLLC_SS_PREG 0x52 #define SIERRA_CMN_PLLLC_SS_AMP_STEP_SIZE_PREG 0x53 #define SIERRA_CMN_PLLLC_SSTWOPT_PREG 0x54 +#define SIERRA_CMN_PLLCSM_PLLEN_TMR_PREG 0x5D +#define SIERRA_CMN_PLLCSM_PLLPRE_TMR_PREG 0x5E #define SIERRA_CMN_PLLLC_SS_TIME_STEPSIZE_MODE_PREG 0x62 #define SIERRA_CMN_PLLLC_LOCK_DELAY_CTRL_PREG 0x63 +#define SIERRA_SDOSCCAL_CLK_CNT_PREG 0x6E #define SIERRA_CMN_REFRCV_PREG 0x98 +#define SIERRA_CMN_RESCAL_CTRLA_PREG 0xA0 #define SIERRA_CMN_REFRCV1_PREG 0xB8 #define SIERRA_CMN_PLLLC1_GEN_PREG 0xC2 #define SIERRA_CMN_PLLLC1_FBDIV_INT_PREG 0xC3 +#define SIERRA_CMN_PLLLC1_DCOCAL_CTRL_PREG 0xC5 #define SIERRA_CMN_PLLLC1_LF_COEFF_MODE0_PREG 0xCA #define SIERRA_CMN_PLLLC1_CLK0_PREG 0xCE #define SIERRA_CMN_PLLLC1_BWCAL_MODE0_PREG 0xD0 @@ -86,6 +97,7 @@ #define SIERRA_DFE_BIASTRIM_PREG 0x04C #define SIERRA_DRVCTRL_ATTEN_PREG 0x06A #define SIERRA_DRVCTRL_BOOST_PREG 0x06F +#define SIERRA_LANE_TX_RECEIVER_DETECT_PREG 0x071 #define SIERRA_TX_RCVDET_OVRD_PREG 0x072 #define SIERRA_CLKPATHCTRL_TMR_PREG 0x081 #define SIERRA_RX_CREQ_FLTR_A_MODE3_PREG 0x085 @@ -101,6 +113,8 @@ #define SIERRA_CREQ_SPARE_PREG 0x096 #define SIERRA_CREQ_EQ_OPEN_EYE_THRESH_PREG 0x097 #define SIERRA_CTLELUT_CTRL_PREG 0x098 +#define SIERRA_DEQ_BLK_TAU_CTRL1_PREG 0x0AC +#define SIERRA_DEQ_BLK_TAU_CTRL4_PREG 0x0AF #define SIERRA_DFE_ECMP_RATESEL_PREG 0x0C0 #define SIERRA_DFE_SMP_RATESEL_PREG 0x0C1 #define SIERRA_DEQ_PHALIGN_CTRL 0x0C4 @@ -129,6 +143,9 @@ #define SIERRA_DEQ_GLUT14 0x0F6 #define SIERRA_DEQ_GLUT15 0x0F7 #define SIERRA_DEQ_GLUT16 0x0F8 +#define SIERRA_POSTPRECUR_EN_CEPH_CTRL_PREG 0x0F9 +#define SIERRA_TAU_EN_CEPH2TO0_PREG 0x0FB +#define SIERRA_TAU_EN_CEPH5TO3_PREG 0x0FC #define SIERRA_DEQ_ALUT0 0x108 #define SIERRA_DEQ_ALUT1 0x109 #define SIERRA_DEQ_ALUT2 0x10A @@ -143,6 +160,7 @@ #define SIERRA_DEQ_ALUT11 0x113 #define SIERRA_DEQ_ALUT12 0x114 #define SIERRA_DEQ_ALUT13 0x115 +#define SIERRA_OEPH_EN_CTRL_PREG 0x124 #define SIERRA_DEQ_DFETAP_CTRL_PREG 0x128 #define SIERRA_DEQ_DFETAP0 0x129 #define SIERRA_DEQ_DFETAP1 0x12B @@ -157,6 +175,7 @@ #define SIERRA_DEQ_TAU_CTRL2_PREG 0x151 #define SIERRA_DEQ_TAU_CTRL3_PREG 0x152 #define SIERRA_DEQ_OPENEYE_CTRL_PREG 0x158 +#define SIERRA_DEQ_CONCUR_EPIOFFSET_MODE_PREG 0x159 #define SIERRA_DEQ_PICTRL_PREG 0x161 #define SIERRA_CPICAL_TMRVAL_MODE1_PREG 0x170 #define SIERRA_CPICAL_TMRVAL_MODE0_PREG 0x171 @@ -165,6 +184,7 @@ #define SIERRA_CPI_RESBIAS_BIN_PREG 0x17E #define SIERRA_CPI_TRIM_PREG 0x17F #define SIERRA_CPICAL_RES_STARTCODE_MODE23_PREG 0x183 +#define SIERRA_CPICAL_RES_STARTCODE_MODE01_PREG 0x184 #define SIERRA_EPI_CTRL_PREG 0x187 #define SIERRA_LFPSDET_SUPPORT_PREG 0x188 #define SIERRA_LFPSFILT_NS_PREG 0x18A @@ -176,6 +196,7 @@ #define SIERRA_RXBUFFER_CTLECTRL_PREG 0x19E #define SIERRA_RXBUFFER_RCDFECTRL_PREG 0x19F #define SIERRA_RXBUFFER_DFECTRL_PREG 0x1A0 +#define SIERRA_LN_SPARE_REG_PREG 0x1B0 #define SIERRA_DEQ_TAU_CTRL1_FAST_MAINT_PREG 0x14F #define SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG 0x150 @@ -2402,6 +2423,77 @@ static struct cdns_sierra_vals usb_100_ext_ssc_ln_vals = { .num_regs = ARRAY_SIZE(cdns_usb_ln_regs_ext_ssc), }; +/* SGMII PHY common configuration */ +static const struct cdns_reg_pairs sgmii_pma_cmn_vals[] = { + {0x0180, SIERRA_SDOSCCAL_CLK_CNT_PREG}, + {0x6000, SIERRA_CMN_REFRCV_PREG}, + {0x0031, SIERRA_CMN_RESCAL_CTRLA_PREG}, + {0x001C, SIERRA_CMN_PLLLC_FBDIV_INT_MODE0_PREG}, + {0x2106, SIERRA_CMN_PLLLC_LF_COEFF_MODE0_PREG}, + {0x0000, SIERRA_CMN_PLLLC_LOCKSEARCH_PREG}, + {0x8103, SIERRA_CMN_PLLLC_CLK0_PREG}, + {0x0000, SIERRA_CMN_PLLLC_BWCAL_MODE0_PREG}, + {0x0027, SIERRA_CMN_PLLCSM_PLLEN_TMR_PREG}, + {0x0062, SIERRA_CMN_PLLCSM_PLLPRE_TMR_PREG}, + {0x0800, SIERRA_CMN_PLLLC_SS_TIME_STEPSIZE_MODE_PREG}, + {0x0000, SIERRA_CMN_PLLLC_INIT_PREG}, + {0x0000, SIERRA_CMN_PLLLC_ITERTMR_PREG}, + {0x0020, SIERRA_CMN_PLLLC_LOCK_CNTSTART_PREG}, + {0x0013, SIERRA_CMN_PLLLC_DCOCAL_CTRL_PREG}, + {0x0013, SIERRA_CMN_PLLLC1_DCOCAL_CTRL_PREG}, +}; + +static struct cdns_sierra_vals sgmii_cmn_vals = { + .reg_pairs = sgmii_pma_cmn_vals, + .num_regs = ARRAY_SIZE(sgmii_pma_cmn_vals), +}; + +/* SGMII PHY lane configuration */ +static const struct cdns_reg_pairs sgmii_ln_regs[] = { + {0x691E, SIERRA_DET_STANDEC_D_PREG}, + {0x0FFE, SIERRA_PSC_RX_A0_PREG}, + {0x0104, SIERRA_PLLCTRL_FBDIV_MODE01_PREG}, + {0x0013, SIERRA_PLLCTRL_SUBRATE_PREG}, + {0x0106, SIERRA_PLLCTRL_GEN_D_PREG}, + {0x5234, SIERRA_PLLCTRL_CPGAIN_MODE_PREG}, + {0x0000, SIERRA_DRVCTRL_ATTEN_PREG}, + {0x00AB, SIERRA_RX_CREQ_FLTR_A_MODE0_PREG}, + {0x3C0E, SIERRA_CREQ_CCLKDET_MODE01_PREG}, + {0x3220, SIERRA_CREQ_FSMCLK_SEL_PREG}, + {0x0000, SIERRA_CREQ_EQ_CTRL_PREG}, + {0x6320, SIERRA_DEQ_CONCUR_EPIOFFSET_MODE_PREG}, + {0x0000, SIERRA_CPI_OUTBUF_RATESEL_PREG}, + {0x15A2, SIERRA_LN_SPARE_REG_PREG}, + {0x7900, SIERRA_DEQ_BLK_TAU_CTRL1_PREG}, + {0x2202, SIERRA_DEQ_BLK_TAU_CTRL4_PREG}, + {0x2206, SIERRA_DEQ_TAU_CTRL2_PREG}, + {0x0005, SIERRA_LANE_TX_RECEIVER_DETECT_PREG}, + {0x8001, SIERRA_CREQ_SPARE_PREG}, + {0x0000, SIERRA_DEQ_CONCUR_CTRL1_PREG}, + {0xD004, SIERRA_DEQ_CONCUR_CTRL2_PREG}, + {0x0101, SIERRA_DEQ_GLUT9}, + {0x0101, SIERRA_DEQ_GLUT10}, + {0x0101, SIERRA_DEQ_GLUT11}, + {0x0101, SIERRA_DEQ_GLUT12}, + {0x0000, SIERRA_DEQ_GLUT13}, + {0x0000, SIERRA_DEQ_GLUT16}, + {0x0000, SIERRA_POSTPRECUR_EN_CEPH_CTRL_PREG}, + {0x0000, SIERRA_TAU_EN_CEPH2TO0_PREG}, + {0x0003, SIERRA_TAU_EN_CEPH5TO3_PREG}, + {0x0101, SIERRA_DEQ_ALUT8}, + {0x0101, SIERRA_DEQ_ALUT9}, + {0x0100, SIERRA_DEQ_ALUT10}, + {0x0000, SIERRA_OEPH_EN_CTRL_PREG}, + {0x5425, SIERRA_DEQ_OPENEYE_CTRL_PREG}, + {0x7458, SIERRA_CPICAL_RES_STARTCODE_MODE23_PREG}, + {0x321F, SIERRA_CPICAL_RES_STARTCODE_MODE01_PREG}, +}; + +static struct cdns_sierra_vals sgmii_pma_ln_vals = { + .reg_pairs = sgmii_ln_regs, + .num_regs = ARRAY_SIZE(sgmii_ln_regs), +}; + static const struct cdns_sierra_data cdns_map_sierra = { .id_value = SIERRA_MACRO_ID, .block_offset_shift = 0x2, @@ -2449,6 +2541,9 @@ static const struct cdns_sierra_data cdns_map_sierra = { }, }, [TYPE_SGMII] = { + [TYPE_NONE] = { + [NO_SSC] = &sgmii_cmn_vals, + }, [TYPE_PCIE] = { [NO_SSC] = &sgmii_100_no_ssc_plllc1_opt3_cmn_vals, [EXTERNAL_SSC] = &sgmii_100_no_ssc_plllc1_opt3_cmn_vals, @@ -2487,6 +2582,9 @@ static const struct cdns_sierra_data cdns_map_sierra = { }, }, [TYPE_SGMII] = { + [TYPE_NONE] = { + [NO_SSC] = &sgmii_pma_ln_vals, + }, [TYPE_PCIE] = { [NO_SSC] = &sgmii_100_no_ssc_plllc1_opt3_ln_vals, [EXTERNAL_SSC] = &sgmii_100_no_ssc_plllc1_opt3_ln_vals, -- GitLab From 2689c9c4ab6006342fce9dd88a0d63a24cf9c05f Mon Sep 17 00:00:00 2001 From: Minda Chen Date: Thu, 29 Jun 2023 15:51:11 +0800 Subject: [PATCH 0164/3445] dt-bindings: phy: Add StarFive JH7110 USB PHY Add StarFive JH7110 SoC USB 2.0 PHY dt-binding. Signed-off-by: Minda Chen Reviewed-by: Hal Feng Reviewed-by: Rob Herring Reviewed-by: Roger Quadros Link: https://lore.kernel.org/r/20230629075115.11934-2-minda.chen@starfivetech.com Signed-off-by: Vinod Koul --- .../bindings/phy/starfive,jh7110-usb-phy.yaml | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/starfive,jh7110-usb-phy.yaml diff --git a/Documentation/devicetree/bindings/phy/starfive,jh7110-usb-phy.yaml b/Documentation/devicetree/bindings/phy/starfive,jh7110-usb-phy.yaml new file mode 100644 index 0000000000000..269e9f9f12b62 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/starfive,jh7110-usb-phy.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/starfive,jh7110-usb-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive JH7110 USB 2.0 PHY + +maintainers: + - Minda Chen + +properties: + compatible: + const: starfive,jh7110-usb-phy + + reg: + maxItems: 1 + + "#phy-cells": + const: 0 + + clocks: + items: + - description: PHY 125m + - description: app 125m + + clock-names: + items: + - const: 125m + - const: app_125m + +required: + - compatible + - reg + - clocks + - clock-names + - "#phy-cells" + +additionalProperties: false + +examples: + - | + phy@10200000 { + compatible = "starfive,jh7110-usb-phy"; + reg = <0x10200000 0x10000>; + clocks = <&syscrg 95>, + <&stgcrg 6>; + clock-names = "125m", "app_125m"; + #phy-cells = <0>; + }; -- GitLab From 69d41115b83905d77474846cbcea91b84bbb7175 Mon Sep 17 00:00:00 2001 From: Minda Chen Date: Thu, 29 Jun 2023 15:51:12 +0800 Subject: [PATCH 0165/3445] dt-bindings: phy: Add StarFive JH7110 PCIe PHY Add StarFive JH7110 SoC PCIe 2.0 PHY dt-binding. PCIe PHY0 (phy@10210000) can be used as USB 3.0 PHY. Signed-off-by: Minda Chen Reviewed-by: Hal Feng Reviewed-by: Rob Herring Reviewed-by: Roger Quadros Link: https://lore.kernel.org/r/20230629075115.11934-3-minda.chen@starfivetech.com Signed-off-by: Vinod Koul --- .../phy/starfive,jh7110-pcie-phy.yaml | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/starfive,jh7110-pcie-phy.yaml diff --git a/Documentation/devicetree/bindings/phy/starfive,jh7110-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/starfive,jh7110-pcie-phy.yaml new file mode 100644 index 0000000000000..2e83a6164cd1d --- /dev/null +++ b/Documentation/devicetree/bindings/phy/starfive,jh7110-pcie-phy.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/starfive,jh7110-pcie-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive JH7110 PCIe 2.0 PHY + +maintainers: + - Minda Chen + +properties: + compatible: + const: starfive,jh7110-pcie-phy + + reg: + maxItems: 1 + + "#phy-cells": + const: 0 + + starfive,sys-syscon: + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - items: + - description: phandle to System Register Controller sys_syscon node. + - description: PHY connect offset of SYS_SYSCONSAIF__SYSCFG register for USB PHY. + description: + The phandle to System Register Controller syscon node and the PHY connect offset + of SYS_SYSCONSAIF__SYSCFG register. Connect PHY to USB3 controller. + + starfive,stg-syscon: + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - items: + - description: phandle to System Register Controller stg_syscon node. + - description: PHY mode offset of STG_SYSCONSAIF__SYSCFG register. + - description: PHY enable for USB offset of STG_SYSCONSAIF__SYSCFG register. + description: + The phandle to System Register Controller syscon node and the offset + of STG_SYSCONSAIF__SYSCFG register for PCIe PHY. Total 2 regsisters offset. + +required: + - compatible + - reg + - "#phy-cells" + +additionalProperties: false + +examples: + - | + phy@10210000 { + compatible = "starfive,jh7110-pcie-phy"; + reg = <0x10210000 0x10000>; + #phy-cells = <0>; + starfive,sys-syscon = <&sys_syscon 0x18>; + starfive,stg-syscon = <&stg_syscon 0x148 0x1f4>; + }; -- GitLab From 16d3a71c20cf2e7cb5f0fef669fe8dc7c2cfd87d Mon Sep 17 00:00:00 2001 From: Minda Chen Date: Thu, 29 Jun 2023 15:51:13 +0800 Subject: [PATCH 0166/3445] phy: starfive: Add JH7110 USB 2.0 PHY driver Add Starfive JH7110 SoC USB 2.0 PHY driver support. USB 2.0 PHY default connect to Cadence USB controller. Signed-off-by: Minda Chen Reviewed-by: Roger Quadros Link: https://lore.kernel.org/r/20230629075115.11934-4-minda.chen@starfivetech.com Signed-off-by: Vinod Koul --- MAINTAINERS | 6 + drivers/phy/Kconfig | 1 + drivers/phy/Makefile | 1 + drivers/phy/starfive/Kconfig | 14 +++ drivers/phy/starfive/Makefile | 2 + drivers/phy/starfive/phy-jh7110-usb.c | 152 ++++++++++++++++++++++++++ 6 files changed, 176 insertions(+) create mode 100644 drivers/phy/starfive/Kconfig create mode 100644 drivers/phy/starfive/Makefile create mode 100644 drivers/phy/starfive/phy-jh7110-usb.c diff --git a/MAINTAINERS b/MAINTAINERS index 3be1bdfe8ecc7..ee455f0a7ed3c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20335,6 +20335,12 @@ S: Supported F: Documentation/devicetree/bindings/watchdog/starfive* F: drivers/watchdog/starfive-wdt.c +STARFIVE JH71X0 USB PHY DRIVER +M: Minda Chen +S: Supported +F: Documentation/devicetree/bindings/phy/starfive,jh7110-usb-phy.yaml +F: drivers/phy/starfive/phy-jh7110-usb.c + STATIC BRANCH/CALL M: Peter Zijlstra M: Josh Poimboeuf diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 8dba9596408f2..e4502958fd62d 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -92,6 +92,7 @@ source "drivers/phy/rockchip/Kconfig" source "drivers/phy/samsung/Kconfig" source "drivers/phy/socionext/Kconfig" source "drivers/phy/st/Kconfig" +source "drivers/phy/starfive/Kconfig" source "drivers/phy/sunplus/Kconfig" source "drivers/phy/tegra/Kconfig" source "drivers/phy/ti/Kconfig" diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 54f312c10a408..fb3dc9de61115 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -31,6 +31,7 @@ obj-y += allwinner/ \ samsung/ \ socionext/ \ st/ \ + starfive/ \ sunplus/ \ tegra/ \ ti/ \ diff --git a/drivers/phy/starfive/Kconfig b/drivers/phy/starfive/Kconfig new file mode 100644 index 0000000000000..65b5f879bbf9f --- /dev/null +++ b/drivers/phy/starfive/Kconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Phy drivers for StarFive platforms +# + +config PHY_STARFIVE_JH7110_USB + tristate "Starfive JH7110 USB 2.0 PHY support" + depends on USB_SUPPORT + select GENERIC_PHY + help + Enable this to support the StarFive USB 2.0 PHY, + used with the Cadence USB controller. + If M is selected, the module will be called + phy-jh7110-usb.ko. diff --git a/drivers/phy/starfive/Makefile b/drivers/phy/starfive/Makefile new file mode 100644 index 0000000000000..52e9a09cc6193 --- /dev/null +++ b/drivers/phy/starfive/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_PHY_STARFIVE_JH7110_USB) += phy-jh7110-usb.o diff --git a/drivers/phy/starfive/phy-jh7110-usb.c b/drivers/phy/starfive/phy-jh7110-usb.c new file mode 100644 index 0000000000000..633912f8a05d0 --- /dev/null +++ b/drivers/phy/starfive/phy-jh7110-usb.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * StarFive JH7110 USB 2.0 PHY driver + * + * Copyright (C) 2023 StarFive Technology Co., Ltd. + * Author: Minda Chen + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define USB_125M_CLK_RATE 125000000 +#define USB_LS_KEEPALIVE_OFF 0x4 +#define USB_LS_KEEPALIVE_ENABLE BIT(4) + +struct jh7110_usb2_phy { + struct phy *phy; + void __iomem *regs; + struct clk *usb_125m_clk; + struct clk *app_125m; + enum phy_mode mode; +}; + +static void usb2_set_ls_keepalive(struct jh7110_usb2_phy *phy, bool set) +{ + unsigned int val; + + /* Host mode enable the LS speed keep-alive signal */ + val = readl(phy->regs + USB_LS_KEEPALIVE_OFF); + if (set) + val |= USB_LS_KEEPALIVE_ENABLE; + else + val &= ~USB_LS_KEEPALIVE_ENABLE; + + writel(val, phy->regs + USB_LS_KEEPALIVE_OFF); +} + +static int usb2_phy_set_mode(struct phy *_phy, + enum phy_mode mode, int submode) +{ + struct jh7110_usb2_phy *phy = phy_get_drvdata(_phy); + + switch (mode) { + case PHY_MODE_USB_HOST: + case PHY_MODE_USB_DEVICE: + case PHY_MODE_USB_OTG: + break; + default: + return -EINVAL; + } + + if (mode != phy->mode) { + dev_dbg(&_phy->dev, "Changing phy to %d\n", mode); + phy->mode = mode; + usb2_set_ls_keepalive(phy, (mode != PHY_MODE_USB_DEVICE)); + } + + return 0; +} + +static int jh7110_usb2_phy_init(struct phy *_phy) +{ + struct jh7110_usb2_phy *phy = phy_get_drvdata(_phy); + int ret; + + ret = clk_set_rate(phy->usb_125m_clk, USB_125M_CLK_RATE); + if (ret) + return ret; + + ret = clk_prepare_enable(phy->app_125m); + if (ret) + return ret; + + return 0; +} + +static int jh7110_usb2_phy_exit(struct phy *_phy) +{ + struct jh7110_usb2_phy *phy = phy_get_drvdata(_phy); + + clk_disable_unprepare(phy->app_125m); + + return 0; +} + +static const struct phy_ops jh7110_usb2_phy_ops = { + .init = jh7110_usb2_phy_init, + .exit = jh7110_usb2_phy_exit, + .set_mode = usb2_phy_set_mode, + .owner = THIS_MODULE, +}; + +static int jh7110_usb_phy_probe(struct platform_device *pdev) +{ + struct jh7110_usb2_phy *phy; + struct device *dev = &pdev->dev; + struct phy_provider *phy_provider; + + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + phy->usb_125m_clk = devm_clk_get(dev, "125m"); + if (IS_ERR(phy->usb_125m_clk)) + return dev_err_probe(dev, PTR_ERR(phy->usb_125m_clk), + "Failed to get 125m clock\n"); + + phy->app_125m = devm_clk_get(dev, "app_125m"); + if (IS_ERR(phy->app_125m)) + return dev_err_probe(dev, PTR_ERR(phy->app_125m), + "Failed to get app 125m clock\n"); + + phy->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(phy->regs)) + return dev_err_probe(dev, PTR_ERR(phy->regs), + "Failed to map phy base\n"); + + phy->phy = devm_phy_create(dev, NULL, &jh7110_usb2_phy_ops); + if (IS_ERR(phy->phy)) + return dev_err_probe(dev, PTR_ERR(phy->phy), + "Failed to create phy\n"); + + phy_set_drvdata(phy->phy, phy); + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct of_device_id jh7110_usb_phy_of_match[] = { + { .compatible = "starfive,jh7110-usb-phy" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, jh7110_usb_phy_of_match); + +static struct platform_driver jh7110_usb_phy_driver = { + .probe = jh7110_usb_phy_probe, + .driver = { + .of_match_table = jh7110_usb_phy_of_match, + .name = "jh7110-usb-phy", + } +}; +module_platform_driver(jh7110_usb_phy_driver); + +MODULE_DESCRIPTION("StarFive JH7110 USB 2.0 PHY driver"); +MODULE_AUTHOR("Minda Chen "); +MODULE_LICENSE("GPL"); -- GitLab From fd097f48eea95c9776a8846edfe9e328e9eaf7e2 Mon Sep 17 00:00:00 2001 From: Minda Chen Date: Thu, 29 Jun 2023 15:51:14 +0800 Subject: [PATCH 0167/3445] phy: starfive: Add JH7110 PCIE 2.0 PHY driver Add Starfive JH7110 SoC PCIe 2.0 PHY driver support. PCIe 2.0 PHY default connect to PCIe controller. PCIe PHY can connect to USB 3.0 controller. Signed-off-by: Minda Chen Reviewed-by: Roger Quadros Link: https://lore.kernel.org/r/20230629075115.11934-5-minda.chen@starfivetech.com Signed-off-by: Vinod Koul --- MAINTAINERS | 4 +- drivers/phy/starfive/Kconfig | 10 ++ drivers/phy/starfive/Makefile | 1 + drivers/phy/starfive/phy-jh7110-pcie.c | 204 +++++++++++++++++++++++++ 4 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 drivers/phy/starfive/phy-jh7110-pcie.c diff --git a/MAINTAINERS b/MAINTAINERS index ee455f0a7ed3c..621b4147d4702 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20335,10 +20335,12 @@ S: Supported F: Documentation/devicetree/bindings/watchdog/starfive* F: drivers/watchdog/starfive-wdt.c -STARFIVE JH71X0 USB PHY DRIVER +STARFIVE JH71X0 PCIE AND USB PHY DRIVER M: Minda Chen S: Supported +F: Documentation/devicetree/bindings/phy/starfive,jh7110-pcie-phy.yaml F: Documentation/devicetree/bindings/phy/starfive,jh7110-usb-phy.yaml +F: drivers/phy/starfive/phy-jh7110-pcie.c F: drivers/phy/starfive/phy-jh7110-usb.c STATIC BRANCH/CALL diff --git a/drivers/phy/starfive/Kconfig b/drivers/phy/starfive/Kconfig index 65b5f879bbf9f..da9a98cdf7e39 100644 --- a/drivers/phy/starfive/Kconfig +++ b/drivers/phy/starfive/Kconfig @@ -3,6 +3,16 @@ # Phy drivers for StarFive platforms # +config PHY_STARFIVE_JH7110_PCIE + tristate "Starfive JH7110 PCIE 2.0/USB 3.0 PHY support" + depends on HAS_IOMEM + select GENERIC_PHY + help + Enable this to support the StarFive PCIe 2.0 PHY, + or used as USB 3.0 PHY. + If M is selected, the module will be called + phy-jh7110-pcie.ko. + config PHY_STARFIVE_JH7110_USB tristate "Starfive JH7110 USB 2.0 PHY support" depends on USB_SUPPORT diff --git a/drivers/phy/starfive/Makefile b/drivers/phy/starfive/Makefile index 52e9a09cc6193..1c62d93e32805 100644 --- a/drivers/phy/starfive/Makefile +++ b/drivers/phy/starfive/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_PHY_STARFIVE_JH7110_PCIE) += phy-jh7110-pcie.o obj-$(CONFIG_PHY_STARFIVE_JH7110_USB) += phy-jh7110-usb.o diff --git a/drivers/phy/starfive/phy-jh7110-pcie.c b/drivers/phy/starfive/phy-jh7110-pcie.c new file mode 100644 index 0000000000000..cbe79c1f59d33 --- /dev/null +++ b/drivers/phy/starfive/phy-jh7110-pcie.c @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * StarFive JH7110 PCIe 2.0 PHY driver + * + * Copyright (C) 2023 StarFive Technology Co., Ltd. + * Author: Minda Chen + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PCIE_KVCO_LEVEL_OFF 0x28 +#define PCIE_USB3_PHY_PLL_CTL_OFF 0x7c +#define PCIE_KVCO_TUNE_SIGNAL_OFF 0x80 +#define PCIE_USB3_PHY_ENABLE BIT(4) +#define PHY_KVCO_FINE_TUNE_LEVEL 0x91 +#define PHY_KVCO_FINE_TUNE_SIGNALS 0xc + +#define USB_PDRSTN_SPLIT BIT(17) + +#define PCIE_PHY_MODE BIT(20) +#define PCIE_PHY_MODE_MASK GENMASK(21, 20) +#define PCIE_USB3_BUS_WIDTH_MASK GENMASK(3, 2) +#define PCIE_USB3_BUS_WIDTH BIT(3) +#define PCIE_USB3_RATE_MASK GENMASK(6, 5) +#define PCIE_USB3_RX_STANDBY_MASK BIT(7) +#define PCIE_USB3_PHY_ENABLE BIT(4) + +struct jh7110_pcie_phy { + struct phy *phy; + struct regmap *stg_syscon; + struct regmap *sys_syscon; + void __iomem *regs; + u32 sys_phy_connect; + u32 stg_pcie_mode; + u32 stg_pcie_usb; + enum phy_mode mode; +}; + +static int phy_usb3_mode_set(struct jh7110_pcie_phy *data) +{ + if (!data->stg_syscon || !data->sys_syscon) { + dev_err(&data->phy->dev, "doesn't support usb3 mode\n"); + return -EINVAL; + } + + regmap_update_bits(data->stg_syscon, data->stg_pcie_mode, + PCIE_PHY_MODE_MASK, PCIE_PHY_MODE); + regmap_update_bits(data->stg_syscon, data->stg_pcie_usb, + PCIE_USB3_BUS_WIDTH_MASK, 0); + regmap_update_bits(data->stg_syscon, data->stg_pcie_usb, + PCIE_USB3_PHY_ENABLE, PCIE_USB3_PHY_ENABLE); + + /* Connect usb 3.0 phy mode */ + regmap_update_bits(data->sys_syscon, data->sys_phy_connect, + USB_PDRSTN_SPLIT, 0); + + /* Configuare spread-spectrum mode: down-spread-spectrum */ + writel(PCIE_USB3_PHY_ENABLE, data->regs + PCIE_USB3_PHY_PLL_CTL_OFF); + + return 0; +} + +static void phy_pcie_mode_set(struct jh7110_pcie_phy *data) +{ + u32 val; + + /* default is PCIe mode */ + if (!data->stg_syscon || !data->sys_syscon) + return; + + regmap_update_bits(data->stg_syscon, data->stg_pcie_mode, + PCIE_PHY_MODE_MASK, 0); + regmap_update_bits(data->stg_syscon, data->stg_pcie_usb, + PCIE_USB3_BUS_WIDTH_MASK, + PCIE_USB3_BUS_WIDTH); + regmap_update_bits(data->stg_syscon, data->stg_pcie_usb, + PCIE_USB3_PHY_ENABLE, 0); + + regmap_update_bits(data->sys_syscon, data->sys_phy_connect, + USB_PDRSTN_SPLIT, 0); + + val = readl(data->regs + PCIE_USB3_PHY_PLL_CTL_OFF); + val &= ~PCIE_USB3_PHY_ENABLE; + writel(val, data->regs + PCIE_USB3_PHY_PLL_CTL_OFF); +} + +static void phy_kvco_gain_set(struct jh7110_pcie_phy *phy) +{ + /* PCIe Multi-PHY PLL KVCO Gain fine tune settings: */ + writel(PHY_KVCO_FINE_TUNE_LEVEL, phy->regs + PCIE_KVCO_LEVEL_OFF); + writel(PHY_KVCO_FINE_TUNE_SIGNALS, phy->regs + PCIE_KVCO_TUNE_SIGNAL_OFF); +} + +static int jh7110_pcie_phy_set_mode(struct phy *_phy, + enum phy_mode mode, int submode) +{ + struct jh7110_pcie_phy *phy = phy_get_drvdata(_phy); + int ret; + + if (mode == phy->mode) + return 0; + + switch (mode) { + case PHY_MODE_USB_HOST: + case PHY_MODE_USB_DEVICE: + case PHY_MODE_USB_OTG: + ret = phy_usb3_mode_set(phy); + if (ret) + return ret; + break; + case PHY_MODE_PCIE: + phy_pcie_mode_set(phy); + break; + default: + return -EINVAL; + } + + dev_dbg(&_phy->dev, "Changing phy mode to %d\n", mode); + phy->mode = mode; + + return 0; +} + +static const struct phy_ops jh7110_pcie_phy_ops = { + .set_mode = jh7110_pcie_phy_set_mode, + .owner = THIS_MODULE, +}; + +static int jh7110_pcie_phy_probe(struct platform_device *pdev) +{ + struct jh7110_pcie_phy *phy; + struct device *dev = &pdev->dev; + struct phy_provider *phy_provider; + u32 args[2]; + + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + phy->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(phy->regs)) + return PTR_ERR(phy->regs); + + phy->phy = devm_phy_create(dev, NULL, &jh7110_pcie_phy_ops); + if (IS_ERR(phy->phy)) + return dev_err_probe(dev, PTR_ERR(phy->regs), + "Failed to map phy base\n"); + + phy->sys_syscon = + syscon_regmap_lookup_by_phandle_args(pdev->dev.of_node, + "starfive,sys-syscon", + 1, args); + + if (!IS_ERR_OR_NULL(phy->sys_syscon)) + phy->sys_phy_connect = args[0]; + else + phy->sys_syscon = NULL; + + phy->stg_syscon = + syscon_regmap_lookup_by_phandle_args(pdev->dev.of_node, + "starfive,stg-syscon", + 2, args); + + if (!IS_ERR_OR_NULL(phy->stg_syscon)) { + phy->stg_pcie_mode = args[0]; + phy->stg_pcie_usb = args[1]; + } else { + phy->stg_syscon = NULL; + } + + phy_kvco_gain_set(phy); + + phy_set_drvdata(phy->phy, phy); + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct of_device_id jh7110_pcie_phy_of_match[] = { + { .compatible = "starfive,jh7110-pcie-phy" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, jh7110_pcie_phy_of_match); + +static struct platform_driver jh7110_pcie_phy_driver = { + .probe = jh7110_pcie_phy_probe, + .driver = { + .of_match_table = jh7110_pcie_phy_of_match, + .name = "jh7110-pcie-phy", + } +}; +module_platform_driver(jh7110_pcie_phy_driver); + +MODULE_DESCRIPTION("StarFive JH7110 PCIe 2.0 PHY driver"); +MODULE_AUTHOR("Minda Chen "); +MODULE_LICENSE("GPL"); -- GitLab From dc5cb63592bd8c1de1fc6647ac7da44deacc9e4c Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 11 Jul 2023 17:51:43 +0300 Subject: [PATCH 0168/3445] dt-bindings: phy: migrate QMP UFS PHY bindings to qcom,sc8280xp-qmp-ufs-phy.yaml Migrate legacy bindings (described in qcom,msm8996-qmp-ufs-phy.yaml) to qcom,sc8280xp-qmp-ufs-phy.yaml. This removes a need to declare the child PHY node or split resource regions. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230711145153.4167820-2-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- .../phy/qcom,msm8996-qmp-ufs-phy.yaml | 228 ------------------ .../phy/qcom,sc8280xp-qmp-ufs-phy.yaml | 48 +++- 2 files changed, 45 insertions(+), 231 deletions(-) delete mode 100644 Documentation/devicetree/bindings/phy/qcom,msm8996-qmp-ufs-phy.yaml diff --git a/Documentation/devicetree/bindings/phy/qcom,msm8996-qmp-ufs-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,msm8996-qmp-ufs-phy.yaml deleted file mode 100644 index 881ba543fd465..0000000000000 --- a/Documentation/devicetree/bindings/phy/qcom,msm8996-qmp-ufs-phy.yaml +++ /dev/null @@ -1,228 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/phy/qcom,msm8996-qmp-ufs-phy.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Qualcomm QMP PHY controller (UFS, MSM8996) - -maintainers: - - Vinod Koul - -description: - QMP PHY controller supports physical layer functionality for a number of - controllers on Qualcomm chipsets, such as, PCIe, UFS, and USB. - - Note that these bindings are for SoCs up to SC8180X. For newer SoCs, see - qcom,sc8280xp-qmp-ufs-phy.yaml. - -properties: - compatible: - enum: - - qcom,msm8996-qmp-ufs-phy - - qcom,msm8998-qmp-ufs-phy - - qcom,sc8180x-qmp-ufs-phy - - qcom,sdm845-qmp-ufs-phy - - qcom,sm6115-qmp-ufs-phy - - qcom,sm6350-qmp-ufs-phy - - qcom,sm8150-qmp-ufs-phy - - qcom,sm8250-qmp-ufs-phy - - qcom,sm8350-qmp-ufs-phy - - qcom,sm8450-qmp-ufs-phy - - reg: - items: - - description: serdes - - "#address-cells": - enum: [ 1, 2 ] - - "#size-cells": - enum: [ 1, 2 ] - - ranges: true - - clocks: - minItems: 1 - maxItems: 3 - - clock-names: - minItems: 1 - maxItems: 3 - - power-domains: - maxItems: 1 - - resets: - maxItems: 1 - - reset-names: - items: - - const: ufsphy - - vdda-phy-supply: true - - vdda-pll-supply: true - - vddp-ref-clk-supply: true - -patternProperties: - "^phy@[0-9a-f]+$": - type: object - description: single PHY-provider child node - properties: - reg: - minItems: 3 - maxItems: 6 - - "#clock-cells": - const: 1 - - "#phy-cells": - const: 0 - - required: - - reg - - "#phy-cells" - - additionalProperties: false - -required: - - compatible - - reg - - "#address-cells" - - "#size-cells" - - ranges - - clocks - - clock-names - - resets - - reset-names - - vdda-phy-supply - - vdda-pll-supply - -additionalProperties: false - -allOf: - - if: - properties: - compatible: - contains: - enum: - - qcom,msm8996-qmp-ufs-phy - then: - properties: - clocks: - maxItems: 1 - clock-names: - items: - - const: ref - - - if: - properties: - compatible: - contains: - enum: - - qcom,msm8998-qmp-ufs-phy - - qcom,sc8180x-qmp-ufs-phy - - qcom,sdm845-qmp-ufs-phy - - qcom,sm6115-qmp-ufs-phy - - qcom,sm6350-qmp-ufs-phy - - qcom,sm8150-qmp-ufs-phy - - qcom,sm8250-qmp-ufs-phy - then: - properties: - clocks: - maxItems: 2 - clock-names: - items: - - const: ref - - const: ref_aux - - - if: - properties: - compatible: - contains: - enum: - - qcom,sm8450-qmp-ufs-phy - then: - properties: - clocks: - maxItems: 3 - clock-names: - items: - - const: ref - - const: ref_aux - - const: qref - - - if: - properties: - compatible: - contains: - enum: - - qcom,msm8998-qmp-ufs-phy - - qcom,sc8180x-qmp-ufs-phy - - qcom,sdm845-qmp-ufs-phy - - qcom,sm6350-qmp-ufs-phy - - qcom,sm8150-qmp-ufs-phy - - qcom,sm8250-qmp-ufs-phy - - qcom,sm8350-qmp-ufs-phy - - qcom,sm8450-qmp-ufs-phy - then: - patternProperties: - "^phy@[0-9a-f]+$": - properties: - reg: - items: - - description: TX lane 1 - - description: RX lane 1 - - description: PCS - - description: TX lane 2 - - description: RX lane 2 - - - if: - properties: - compatible: - contains: - enum: - - qcom,msm8996-qmp-ufs-phy - - qcom,sm6115-qmp-ufs-phy - then: - patternProperties: - "^phy@[0-9a-f]+$": - properties: - reg: - items: - - description: TX - - description: RX - - description: PCS - -examples: - - | - #include - #include - - phy-wrapper@1d87000 { - compatible = "qcom,sm8250-qmp-ufs-phy"; - reg = <0x01d87000 0x1c0>; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0x01d87000 0x1000>; - - clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_UFS_PHY_PHY_AUX_CLK>; - clock-names = "ref", "ref_aux"; - - resets = <&ufs_mem_hc 0>; - reset-names = "ufsphy"; - - vdda-phy-supply = <&vreg_l6b>; - vdda-pll-supply = <&vreg_l3b>; - - phy@400 { - reg = <0x400 0x108>, - <0x600 0x1e0>, - <0xc00 0x1dc>, - <0x800 0x108>, - <0xa00 0x1e0>; - #phy-cells = <0>; - }; - }; diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml index a1897a7606df4..d981d77e82e40 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml @@ -16,21 +16,31 @@ description: properties: compatible: enum: + - qcom,msm8996-qmp-ufs-phy + - qcom,msm8998-qmp-ufs-phy - qcom,sa8775p-qmp-ufs-phy + - qcom,sc8180x-qmp-ufs-phy - qcom,sc8280xp-qmp-ufs-phy + - qcom,sdm845-qmp-ufs-phy + - qcom,sm6115-qmp-ufs-phy - qcom,sm6125-qmp-ufs-phy + - qcom,sm6350-qmp-ufs-phy - qcom,sm7150-qmp-ufs-phy + - qcom,sm8150-qmp-ufs-phy + - qcom,sm8250-qmp-ufs-phy + - qcom,sm8350-qmp-ufs-phy + - qcom,sm8450-qmp-ufs-phy - qcom,sm8550-qmp-ufs-phy reg: maxItems: 1 clocks: - minItems: 2 + minItems: 1 maxItems: 3 clock-names: - minItems: 2 + minItems: 1 items: - const: ref - const: ref_aux @@ -75,19 +85,51 @@ allOf: contains: enum: - qcom,sa8775p-qmp-ufs-phy + - qcom,sm8450-qmp-ufs-phy then: properties: clocks: minItems: 3 clock-names: minItems: 3 - else: + + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8998-qmp-ufs-phy + - qcom,sc8180x-qmp-ufs-phy + - qcom,sc8280xp-qmp-ufs-phy + - qcom,sdm845-qmp-ufs-phy + - qcom,sm6115-qmp-ufs-phy + - qcom,sm6125-qmp-ufs-phy + - qcom,sm6350-qmp-ufs-phy + - qcom,sm7150-qmp-ufs-phy + - qcom,sm8150-qmp-ufs-phy + - qcom,sm8250-qmp-ufs-phy + - qcom,sm8350-qmp-ufs-phy + - qcom,sm8550-qmp-ufs-phy + then: properties: clocks: maxItems: 2 clock-names: maxItems: 2 + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8996-qmp-ufs-phy + then: + properties: + clocks: + maxItems: 1 + clock-names: + maxItems: 1 + additionalProperties: false examples: -- GitLab From 20b5c6ae18ffdbac410f1711c932cf0fd80d2539 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 11 Jul 2023 17:51:44 +0300 Subject: [PATCH 0169/3445] phy: qcom-qmp-ufs: populate offsets configuration Populate offsets configuration for the rest of UFS PHYs to make it possible to switch them to the new (single-node) bindings style. Reviewed-by: Bjorn Andersson Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230711145153.4167820-3-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index 8c877b668bb97..d99dc1043f74e 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -833,6 +833,8 @@ static const struct qmp_ufs_offsets qmp_ufs_offsets_v6 = { static const struct qmp_phy_cfg msm8996_ufsphy_cfg = { .lanes = 1, + .offsets = &qmp_ufs_offsets, + .tbls = { .serdes = msm8996_ufsphy_serdes, .serdes_num = ARRAY_SIZE(msm8996_ufsphy_serdes), @@ -924,6 +926,8 @@ static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = { static const struct qmp_phy_cfg sdm845_ufsphy_cfg = { .lanes = 2, + .offsets = &qmp_ufs_offsets, + .tbls = { .serdes = sdm845_ufsphy_serdes, .serdes_num = ARRAY_SIZE(sdm845_ufsphy_serdes), @@ -1038,6 +1042,8 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = { static const struct qmp_phy_cfg sm8250_ufsphy_cfg = { .lanes = 2, + .offsets = &qmp_ufs_offsets, + .tbls = { .serdes = sm8150_ufsphy_serdes, .serdes_num = ARRAY_SIZE(sm8150_ufsphy_serdes), @@ -1070,6 +1076,8 @@ static const struct qmp_phy_cfg sm8250_ufsphy_cfg = { static const struct qmp_phy_cfg sm8350_ufsphy_cfg = { .lanes = 2, + .offsets = &qmp_ufs_offsets, + .tbls = { .serdes = sm8350_ufsphy_serdes, .serdes_num = ARRAY_SIZE(sm8350_ufsphy_serdes), @@ -1102,6 +1110,8 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = { static const struct qmp_phy_cfg sm8450_ufsphy_cfg = { .lanes = 2, + .offsets = &qmp_ufs_offsets, + .tbls = { .serdes = sm8350_ufsphy_serdes, .serdes_num = ARRAY_SIZE(sm8350_ufsphy_serdes), -- GitLab From 76009ee76e05e30e29aade02e788aebe9ce9ffd2 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 11 Jul 2023 15:45:39 -0400 Subject: [PATCH 0170/3445] phy: zynqmp: Allow variation in refclk rate Due to limited available frequency ratios, the reference clock rate may not be exactly the same as the required rate. Allow a small (100 ppm) deviation. Signed-off-by: Sean Anderson Link: https://lore.kernel.org/r/20230711194542.898230-1-sean.anderson@seco.com Signed-off-by: Vinod Koul --- drivers/phy/xilinx/phy-zynqmp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/phy/xilinx/phy-zynqmp.c b/drivers/phy/xilinx/phy-zynqmp.c index b0c2045b886ee..2559c6594cea2 100644 --- a/drivers/phy/xilinx/phy-zynqmp.c +++ b/drivers/phy/xilinx/phy-zynqmp.c @@ -904,7 +904,10 @@ static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev) rate = clk_get_rate(clk); for (i = 0 ; i < ARRAY_SIZE(ssc_lookup); i++) { - if (rate == ssc_lookup[i].refclk_rate) { + /* Allow an error of 100 ppm */ + unsigned long error = ssc_lookup[i].refclk_rate / 10000; + + if (abs(rate - ssc_lookup[i].refclk_rate) < error) { gtr_dev->refclk_sscs[refclk] = &ssc_lookup[i]; break; } -- GitLab From 0b64150c34290df5bf962b3b7e45389b0acb03ae Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 12 Jul 2023 11:53:23 -0700 Subject: [PATCH 0171/3445] Input: bcm-keypad - correct dev_err_probe() error Pass proper PTR_ERR as dev_err_probe() argument. Fixes: a2c795b696b2 ("Input: bcm-keypad - simplify with dev_err_probe()") Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202306261505.wTjCXRIO-lkp@intel.com/ Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230711072449.43569-1-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/bcm-keypad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/keyboard/bcm-keypad.c b/drivers/input/keyboard/bcm-keypad.c index 0aa6ef0da0eea..f3c3746acd4cf 100644 --- a/drivers/input/keyboard/bcm-keypad.c +++ b/drivers/input/keyboard/bcm-keypad.c @@ -359,7 +359,7 @@ static int bcm_kp_probe(struct platform_device *pdev) /* Enable clock */ kp->clk = devm_clk_get_optional(&pdev->dev, "peri_clk"); if (IS_ERR(kp->clk)) { - return dev_err_probe(&pdev->dev, error, "Failed to get clock\n"); + return dev_err_probe(&pdev->dev, PTR_ERR(kp->clk), "Failed to get clock\n"); } else if (!kp->clk) { dev_dbg(&pdev->dev, "No clock specified. Assuming it's enabled\n"); } else { -- GitLab From eb09074bdb05ffd6bfe77f8b4a41b76ef78c997b Mon Sep 17 00:00:00 2001 From: Werner Sembach Date: Wed, 12 Jul 2023 11:56:51 -0700 Subject: [PATCH 0172/3445] Input: i8042 - add quirk for TUXEDO Gemini 17 Gen1/Clevo PD70PN The touchpad of this device is both connected via PS/2 and i2c. This causes strange behavior when both driver fight for control. The easy fix is to prevent the PS/2 driver from accessing the mouse port as the full feature set of the touchpad is only supported in the i2c interface anyway. The strange behavior in this case is, that when an external screen is connected and the notebook is closed, the pointer on the external screen is moving to the lower right corner. When the notebook is opened again, this movement stops, but the touchpad clicks are unresponsive afterwards until reboot. Signed-off-by: Werner Sembach Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20230607173331.851192-1-wse@tuxedocomputers.com Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042-acpipnpio.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h index 028e45bd050bf..1724d6cb8649d 100644 --- a/drivers/input/serio/i8042-acpipnpio.h +++ b/drivers/input/serio/i8042-acpipnpio.h @@ -1281,6 +1281,13 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = { .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) }, + /* See comment on TUXEDO InfinityBook S17 Gen6 / Clevo NS70MU above */ + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "PD5x_7xPNP_PNR_PNN_PNT"), + }, + .driver_data = (void *)(SERIO_QUIRK_NOAUX) + }, { .matches = { DMI_MATCH(DMI_BOARD_NAME, "X170SM"), -- GitLab From 0859c1764c77dd61adf46e3d0c440145118d9e0e Mon Sep 17 00:00:00 2001 From: Roi L Date: Wed, 12 Jul 2023 14:09:06 -0700 Subject: [PATCH 0173/3445] Input: rotary_encoder - don't double assign input->dev.parent devm_input_allocate_device() already assigns the @dev.parent field of the input device/structure, so there's no need to reassign input->dev.parent to dev. Signed-off-by: Roi L Link: https://lore.kernel.org/r/PH0P220MB0460B69CA018F5515F5FACDDDD53A@PH0P220MB0460.NAMP220.PROD.OUTLOOK.COM Signed-off-by: Dmitry Torokhov --- drivers/input/misc/rotary_encoder.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index fb3a34f8eccd2..e94cab8133bec 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -251,7 +251,6 @@ static int rotary_encoder_probe(struct platform_device *pdev) input->name = pdev->name; input->id.bustype = BUS_HOST; - input->dev.parent = dev; if (encoder->relative_axis) input_set_capability(input, EV_REL, encoder->axis); -- GitLab From d6239463206525f2b64bbf9bfeb83a81f0235914 Mon Sep 17 00:00:00 2001 From: Jeff LaBundy Date: Mon, 29 May 2023 19:33:47 -0500 Subject: [PATCH 0174/3445] dt-bindings: input: Add bindings for Azoteq IQS7210A/7211A/E Add bindings for the Azoteq IQS7210A/7211A/E family of trackpad/ touchscreen controllers. Signed-off-by: Jeff LaBundy Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/ZHVEa0yM1LLUJEfO@nixie71 Signed-off-by: Dmitry Torokhov --- .../input/touchscreen/azoteq,iqs7211.yaml | 769 ++++++++++++++++++ 1 file changed, 769 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/azoteq,iqs7211.yaml diff --git a/Documentation/devicetree/bindings/input/touchscreen/azoteq,iqs7211.yaml b/Documentation/devicetree/bindings/input/touchscreen/azoteq,iqs7211.yaml new file mode 100644 index 0000000000000..8cf371b99f19c --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/azoteq,iqs7211.yaml @@ -0,0 +1,769 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/azoteq,iqs7211.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Azoteq IQS7210A/7211A/E Trackpad/Touchscreen Controller + +maintainers: + - Jeff LaBundy + +description: | + The Azoteq IQS7210A, IQS7211A and IQS7211E trackpad and touchscreen control- + lers employ projected-capacitance sensing and can track two contacts. + + Link to datasheets: https://www.azoteq.com/ + +properties: + compatible: + enum: + - azoteq,iqs7210a + - azoteq,iqs7211a + - azoteq,iqs7211e + + reg: + maxItems: 1 + + irq-gpios: + maxItems: 1 + description: + Specifies the GPIO connected to the device's active-low RDY output. The + pin doubles as the IQS7211E's active-low MCLR input, in which case this + GPIO must be configured as open-drain. + + reset-gpios: + maxItems: 1 + description: + Specifies the GPIO connected to the device's active-low MCLR input. The + device is temporarily held in hardware reset prior to initialization if + this property is present. + + azoteq,forced-comms: + type: boolean + description: + Enables forced communication; to be used with host adapters that cannot + tolerate clock stretching. + + azoteq,forced-comms-default: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1] + description: + Indicates if the device's OTP memory enables (1) or disables (0) forced + communication by default. Specifying this property can expedite startup + time if the default value is known. + + If this property is not specified, communication is not initiated until + the device asserts its RDY pin shortly after exiting hardware reset. At + that point, forced communication is either enabled or disabled based on + the presence or absence of the 'azoteq,forced-comms' property. + + azoteq,rate-active-ms: + minimum: 0 + maximum: 65535 + description: Specifies the report rate (in ms) during active mode. + + azoteq,rate-touch-ms: + minimum: 0 + maximum: 65535 + description: Specifies the report rate (in ms) during idle-touch mode. + + azoteq,rate-idle-ms: + minimum: 0 + maximum: 65535 + description: Specifies the report rate (in ms) during idle mode. + + azoteq,rate-lp1-ms: + minimum: 0 + maximum: 65535 + description: Specifies the report rate (in ms) during low-power mode 1. + + azoteq,rate-lp2-ms: + minimum: 0 + maximum: 65535 + description: Specifies the report rate (in ms) during low-power mode 2. + + azoteq,timeout-active-ms: + multipleOf: 1000 + minimum: 0 + maximum: 65535000 + description: + Specifies the length of time (in ms) to wait for an event before moving + from active mode to idle or idle-touch modes. + + azoteq,timeout-touch-ms: + multipleOf: 1000 + minimum: 0 + maximum: 65535000 + description: + Specifies the length of time (in ms) to wait for an event before moving + from idle-touch mode to idle mode. + + azoteq,timeout-idle-ms: + multipleOf: 1000 + minimum: 0 + maximum: 65535000 + description: + Specifies the length of time (in ms) to wait for an event before moving + from idle mode to low-power mode 1. + + azoteq,timeout-lp1-ms: + multipleOf: 1000 + minimum: 0 + maximum: 65535000 + description: + Specifies the length of time (in ms) to wait for an event before moving + from low-power mode 1 to low-power mode 2. + + azoteq,timeout-lp2-ms: + multipleOf: 1000 + minimum: 0 + maximum: 60000 + description: + Specifies the rate (in ms) at which the trackpad reference values + are updated during low-power modes 1 and 2. + + azoteq,timeout-ati-ms: + multipleOf: 1000 + minimum: 0 + maximum: 60000 + description: + Specifies the delay (in ms) before the automatic tuning implementation + (ATI) is retried in the event it fails to complete. + + azoteq,timeout-comms-ms: + minimum: 0 + maximum: 65535 + description: + Specifies the delay (in ms) before a communication window is closed. + + azoteq,timeout-press-ms: + multipleOf: 1000 + minimum: 0 + maximum: 60000 + description: + Specifies the length of time (in ms) to wait before automatically + releasing a press event. Specify zero to allow the press state to + persist indefinitely. + + azoteq,fosc-freq: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1] + description: | + Specifies the device's core clock frequency as follows: + 0: 14 MHz + 1: 18 MHz + + azoteq,fosc-trim: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 15 + description: Specifies the device's core clock frequency trim. + + azoteq,num-contacts: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 2 + default: 0 + description: Specifies the number of contacts reported by the device. + + azoteq,contact-split: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + description: Specifies the contact (finger) split factor. + + azoteq,trim-x: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + description: Specifies the horizontal trim width. + + azoteq,trim-y: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + description: Specifies the vertical trim height. + + trackpad: + type: object + description: Represents all channels associated with the trackpad. + + properties: + azoteq,rx-enable: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 8 + items: + minimum: 0 + maximum: 7 + description: + Specifies the order of the CRx pin(s) associated with the trackpad. + + azoteq,tx-enable: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 12 + items: + minimum: 0 + maximum: 11 + description: + Specifies the order of the CTx pin(s) associated with the trackpad. + + azoteq,channel-select: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 36 + items: + minimum: 0 + maximum: 255 + description: | + Specifies the channels mapped to each cycle in the following order: + Cycle 0, slot 0 + Cycle 0, slot 1 + Cycle 1, slot 0 + Cycle 1, slot 1 + ...and so on. Specify 255 to disable a given slot. + + azoteq,ati-frac-div-fine: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 31 + description: Specifies the trackpad's ATI fine fractional divider. + + azoteq,ati-frac-mult-coarse: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 15 + description: Specifies the trackpad's ATI coarse fractional multiplier. + + azoteq,ati-frac-div-coarse: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 31 + description: Specifies the trackpad's ATI coarse fractional divider. + + azoteq,ati-comp-div: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 31 + description: Specifies the trackpad's ATI compensation divider. + + azoteq,ati-target: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 65535 + description: Specifies the trackpad's ATI target. + + azoteq,touch-enter: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + description: Specifies the trackpad's touch entrance factor. + + azoteq,touch-exit: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + description: Specifies the trackpad's touch exit factor. + + azoteq,thresh: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + description: Specifies the trackpad's stationary touch threshold. + + azoteq,conv-period: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + description: Specifies the trackpad's conversion period. + + azoteq,conv-frac: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + description: Specifies the trackpad's conversion frequency fraction. + + patternProperties: + "^event-(tap(-double|-triple)?|hold|palm|swipe-(x|y)-(pos|neg)(-hold)?)$": + type: object + $ref: ../input.yaml# + description: + Represents a gesture event reported by the trackpad. In the case of + axial gestures, the duration or distance specified in one direction + applies to both directions along the same axis. + + properties: + linux,code: true + + azoteq,gesture-max-ms: + minimum: 0 + maximum: 65535 + description: Specifies the maximum duration of tap/swipe gestures. + + azoteq,gesture-mid-ms: + minimum: 0 + maximum: 65535 + description: + Specifies the maximum duration between subsequent tap gestures + (IQS7211E only). + + azoteq,gesture-min-ms: + minimum: 0 + maximum: 65535 + description: Specifies the minimum duration of hold gestures. + + azoteq,gesture-dist: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 65535 + description: + Specifies the minimum (swipe) or maximum (tap and hold) distance + a finger may travel to be considered a gesture. + + azoteq,gesture-dist-rep: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 65535 + description: + Specifies the minimum distance a finger must travel to elicit a + repeated swipe gesture (IQS7211E only). + + azoteq,gesture-angle: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 75 + description: + Specifies the maximum angle (in degrees) a finger may travel to + be considered a swipe gesture. + + azoteq,thresh: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 42 + description: Specifies the palm gesture threshold (IQS7211E only). + + additionalProperties: false + + dependencies: + azoteq,rx-enable: ["azoteq,tx-enable"] + azoteq,tx-enable: ["azoteq,rx-enable"] + azoteq,channel-select: ["azoteq,rx-enable"] + + additionalProperties: false + + alp: + type: object + $ref: ../input.yaml# + description: Represents the alternate low-power channel (ALP). + + properties: + azoteq,rx-enable: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 8 + items: + minimum: 0 + maximum: 7 + description: + Specifies the CRx pin(s) associated with the ALP in no particular + order. + + azoteq,tx-enable: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 12 + items: + minimum: 0 + maximum: 11 + description: + Specifies the CTx pin(s) associated with the ALP in no particular + order. + + azoteq,ati-frac-div-fine: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 31 + description: Specifies the ALP's ATI fine fractional divider. + + azoteq,ati-frac-mult-coarse: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 15 + description: Specifies the ALP's ATI coarse fractional multiplier. + + azoteq,ati-frac-div-coarse: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 31 + description: Specifies the ALP's ATI coarse fractional divider. + + azoteq,ati-comp-div: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 31 + description: Specifies the ALP's ATI compensation divider. + + azoteq,ati-target: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 65535 + description: Specifies the ALP's ATI target. + + azoteq,ati-base: + $ref: /schemas/types.yaml#/definitions/uint32 + multipleOf: 8 + minimum: 0 + maximum: 255 + description: Specifies the ALP's ATI base. + + azoteq,ati-mode: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1] + description: | + Specifies the ALP's ATI mode as follows: + 0: Partial + 1: Full + + azoteq,sense-mode: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1] + description: | + Specifies the ALP's sensing mode as follows: + 0: Self capacitive + 1: Mutual capacitive + + azoteq,debounce-enter: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + description: Specifies the ALP's debounce entrance factor. + + azoteq,debounce-exit: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + description: Specifies the ALP's debounce exit factor. + + azoteq,thresh: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 65535 + description: Specifies the ALP's proximity or touch threshold. + + azoteq,conv-period: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + description: Specifies the ALP's conversion period. + + azoteq,conv-frac: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + description: Specifies the ALP's conversion frequency fraction. + + linux,code: true + + additionalProperties: false + + button: + type: object + description: Represents the inductive or capacitive button. + + properties: + azoteq,ati-frac-div-fine: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 31 + description: Specifies the button's ATI fine fractional divider. + + azoteq,ati-frac-mult-coarse: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 15 + description: Specifies the button's ATI coarse fractional multiplier. + + azoteq,ati-frac-div-coarse: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 31 + description: Specifies the button's ATI coarse fractional divider. + + azoteq,ati-comp-div: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 31 + description: Specifies the button's ATI compensation divider. + + azoteq,ati-target: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 65535 + description: Specifies the button's ATI target. + + azoteq,ati-base: + $ref: /schemas/types.yaml#/definitions/uint32 + multipleOf: 8 + minimum: 0 + maximum: 255 + description: Specifies the button's ATI base. + + azoteq,ati-mode: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1] + description: | + Specifies the button's ATI mode as follows: + 0: Partial + 1: Full + + azoteq,sense-mode: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2] + description: | + Specifies the button's sensing mode as follows: + 0: Self capacitive + 1: Mutual capacitive + 2: Inductive + + azoteq,touch-enter: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + description: Specifies the button's touch entrance factor. + + azoteq,touch-exit: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + description: Specifies the button's touch exit factor. + + azoteq,debounce-enter: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + description: Specifies the button's debounce entrance factor. + + azoteq,debounce-exit: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + description: Specifies the button's debounce exit factor. + + azoteq,thresh: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 65535 + description: Specifies the button's proximity threshold. + + azoteq,conv-period: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + description: Specifies the button's conversion period. + + azoteq,conv-frac: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + description: Specifies the button's conversion frequency fraction. + + patternProperties: + "^event-(prox|touch)$": + type: object + $ref: ../input.yaml# + description: + Represents a proximity or touch event reported by the button. + + properties: + linux,code: true + + additionalProperties: false + + additionalProperties: false + + wakeup-source: true + + touchscreen-size-x: true + touchscreen-size-y: true + touchscreen-inverted-x: true + touchscreen-inverted-y: true + touchscreen-swapped-x-y: true + +dependencies: + touchscreen-size-x: ["azoteq,num-contacts"] + touchscreen-size-y: ["azoteq,num-contacts"] + touchscreen-inverted-x: ["azoteq,num-contacts"] + touchscreen-inverted-y: ["azoteq,num-contacts"] + touchscreen-swapped-x-y: ["azoteq,num-contacts"] + +required: + - compatible + - reg + - irq-gpios + +additionalProperties: false + +allOf: + - $ref: touchscreen.yaml# + + - if: + properties: + compatible: + contains: + const: azoteq,iqs7210a + + then: + properties: + alp: + properties: + azoteq,rx-enable: + maxItems: 4 + items: + minimum: 4 + + else: + properties: + azoteq,timeout-press-ms: false + + alp: + properties: + azoteq,ati-mode: false + + button: false + + - if: + properties: + compatible: + contains: + const: azoteq,iqs7211e + + then: + properties: + reset-gpios: false + + trackpad: + properties: + azoteq,tx-enable: + maxItems: 13 + items: + maximum: 12 + + alp: + properties: + azoteq,tx-enable: + maxItems: 13 + items: + maximum: 12 + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + touch@56 { + compatible = "azoteq,iqs7210a"; + reg = <0x56>; + irq-gpios = <&gpio 4 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio 17 (GPIO_ACTIVE_LOW | + GPIO_PUSH_PULL)>; + azoteq,num-contacts = <2>; + + trackpad { + azoteq,rx-enable = <6>, <5>, <4>, <3>, <2>; + azoteq,tx-enable = <1>, <7>, <8>, <9>, <10>; + }; + + button { + azoteq,sense-mode = <2>; + azoteq,touch-enter = <40>; + azoteq,touch-exit = <36>; + + event-touch { + linux,code = ; + }; + }; + + alp { + azoteq,sense-mode = <1>; + linux,code = ; + }; + }; + }; + + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + touch@56 { + compatible = "azoteq,iqs7211e"; + reg = <0x56>; + irq-gpios = <&gpio 4 (GPIO_ACTIVE_LOW | + GPIO_OPEN_DRAIN)>; + + trackpad { + event-tap { + linux,code = ; + }; + + event-tap-double { + linux,code = ; + }; + + event-tap-triple { + linux,code = ; + }; + + event-hold { + linux,code = ; + }; + + event-palm { + linux,code = ; + }; + + event-swipe-x-pos { + linux,code = ; + }; + + event-swipe-x-pos-hold { + linux,code = ; + }; + + event-swipe-x-neg { + linux,code = ; + }; + + event-swipe-x-neg-hold { + linux,code = ; + }; + + event-swipe-y-pos { + linux,code = ; + }; + + event-swipe-y-pos-hold { + linux,code = ; + }; + + event-swipe-y-neg { + linux,code = ; + }; + + event-swipe-y-neg-hold { + linux,code = ; + }; + }; + }; + }; + +... -- GitLab From f2ba47e65f3b5642488802a60cb7dd068f425edc Mon Sep 17 00:00:00 2001 From: Jeff LaBundy Date: Mon, 29 May 2023 19:34:00 -0500 Subject: [PATCH 0175/3445] Input: add support for Azoteq IQS7210A/7211A/E Add support for the Azoteq IQS7210A/7211A/E family of trackpad/ touchscreen controllers. Signed-off-by: Jeff LaBundy Link: https://lore.kernel.org/r/ZHVEeDlYyr69A59K@nixie71 Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 10 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/iqs7211.c | 2569 +++++++++++++++++++++++++++ 3 files changed, 2580 insertions(+) create mode 100644 drivers/input/touchscreen/iqs7211.c diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index fb4c23917b69d..e3e2324547b90 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1365,6 +1365,16 @@ config TOUCHSCREEN_IQS5XX To compile this driver as a module, choose M here: the module will be called iqs5xx. +config TOUCHSCREEN_IQS7211 + tristate "Azoteq IQS7210A/7211A/E trackpad/touchscreen controller" + depends on I2C + help + Say Y to enable support for the Azoteq IQS7210A/7211A/E + family of trackpad/touchscreen controllers. + + To compile this driver as a module, choose M here: the + module will be called iqs7211. + config TOUCHSCREEN_ZINITIX tristate "Zinitix touchscreen support" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 159cd5136fdbc..62bd24f3ac8e0 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -115,5 +115,6 @@ obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o obj-$(CONFIG_TOUCHSCREEN_RASPBERRYPI_FW) += raspberrypi-ts.o obj-$(CONFIG_TOUCHSCREEN_IQS5XX) += iqs5xx.o +obj-$(CONFIG_TOUCHSCREEN_IQS7211) += iqs7211.o obj-$(CONFIG_TOUCHSCREEN_ZINITIX) += zinitix.o obj-$(CONFIG_TOUCHSCREEN_HIMAX_HX83112B) += himax_hx83112b.o diff --git a/drivers/input/touchscreen/iqs7211.c b/drivers/input/touchscreen/iqs7211.c new file mode 100644 index 0000000000000..f60316d37f454 --- /dev/null +++ b/drivers/input/touchscreen/iqs7211.c @@ -0,0 +1,2569 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Azoteq IQS7210A/7211A/E Trackpad/Touchscreen Controller + * + * Copyright (C) 2023 Jeff LaBundy + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IQS7211_PROD_NUM 0x00 + +#define IQS7211_EVENT_MASK_ALL GENMASK(14, 8) +#define IQS7211_EVENT_MASK_ALP BIT(13) +#define IQS7211_EVENT_MASK_BTN BIT(12) +#define IQS7211_EVENT_MASK_ATI BIT(11) +#define IQS7211_EVENT_MASK_MOVE BIT(10) +#define IQS7211_EVENT_MASK_GSTR BIT(9) +#define IQS7211_EVENT_MODE BIT(8) + +#define IQS7211_COMMS_ERROR 0xEEEE +#define IQS7211_COMMS_RETRY_MS 50 +#define IQS7211_COMMS_SLEEP_US 100 +#define IQS7211_COMMS_TIMEOUT_US (100 * USEC_PER_MSEC) +#define IQS7211_RESET_TIMEOUT_MS 150 +#define IQS7211_START_TIMEOUT_US (1 * USEC_PER_SEC) + +#define IQS7211_NUM_RETRIES 5 +#define IQS7211_NUM_CRX 8 +#define IQS7211_MAX_CTX 13 + +#define IQS7211_MAX_CONTACTS 2 +#define IQS7211_MAX_CYCLES 21 + +/* + * The following delay is used during instances that must wait for the open- + * drain RDY pin to settle. Its value is calculated as 5*R*C, where R and C + * represent typical datasheet values of 4.7k and 100 nF, respectively. + */ +#define iqs7211_irq_wait() usleep_range(2500, 2600) + +enum iqs7211_dev_id { + IQS7210A, + IQS7211A, + IQS7211E, +}; + +enum iqs7211_comms_mode { + IQS7211_COMMS_MODE_WAIT, + IQS7211_COMMS_MODE_FREE, + IQS7211_COMMS_MODE_FORCE, +}; + +struct iqs7211_reg_field_desc { + struct list_head list; + u8 addr; + u16 mask; + u16 val; +}; + +enum iqs7211_reg_key_id { + IQS7211_REG_KEY_NONE, + IQS7211_REG_KEY_PROX, + IQS7211_REG_KEY_TOUCH, + IQS7211_REG_KEY_TAP, + IQS7211_REG_KEY_HOLD, + IQS7211_REG_KEY_PALM, + IQS7211_REG_KEY_AXIAL_X, + IQS7211_REG_KEY_AXIAL_Y, + IQS7211_REG_KEY_RESERVED +}; + +enum iqs7211_reg_grp_id { + IQS7211_REG_GRP_TP, + IQS7211_REG_GRP_BTN, + IQS7211_REG_GRP_ALP, + IQS7211_REG_GRP_SYS, + IQS7211_NUM_REG_GRPS +}; + +static const char * const iqs7211_reg_grp_names[IQS7211_NUM_REG_GRPS] = { + [IQS7211_REG_GRP_TP] = "trackpad", + [IQS7211_REG_GRP_BTN] = "button", + [IQS7211_REG_GRP_ALP] = "alp", +}; + +static const u16 iqs7211_reg_grp_masks[IQS7211_NUM_REG_GRPS] = { + [IQS7211_REG_GRP_TP] = IQS7211_EVENT_MASK_GSTR, + [IQS7211_REG_GRP_BTN] = IQS7211_EVENT_MASK_BTN, + [IQS7211_REG_GRP_ALP] = IQS7211_EVENT_MASK_ALP, +}; + +struct iqs7211_event_desc { + const char *name; + u16 mask; + u16 enable; + enum iqs7211_reg_grp_id reg_grp; + enum iqs7211_reg_key_id reg_key; +}; + +static const struct iqs7211_event_desc iqs7210a_kp_events[] = { + { + .mask = BIT(10), + .enable = BIT(13) | BIT(12), + .reg_grp = IQS7211_REG_GRP_ALP, + }, + { + .name = "event-prox", + .mask = BIT(2), + .enable = BIT(5) | BIT(4), + .reg_grp = IQS7211_REG_GRP_BTN, + .reg_key = IQS7211_REG_KEY_PROX, + }, + { + .name = "event-touch", + .mask = BIT(3), + .enable = BIT(5) | BIT(4), + .reg_grp = IQS7211_REG_GRP_BTN, + .reg_key = IQS7211_REG_KEY_TOUCH, + }, + { + .name = "event-tap", + .mask = BIT(0), + .enable = BIT(0), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_TAP, + }, + { + .name = "event-hold", + .mask = BIT(1), + .enable = BIT(1), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_HOLD, + }, + { + .name = "event-swipe-x-neg", + .mask = BIT(2), + .enable = BIT(2), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_X, + }, + { + .name = "event-swipe-x-pos", + .mask = BIT(3), + .enable = BIT(3), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_X, + }, + { + .name = "event-swipe-y-pos", + .mask = BIT(4), + .enable = BIT(4), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_Y, + }, + { + .name = "event-swipe-y-neg", + .mask = BIT(5), + .enable = BIT(5), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_Y, + }, +}; + +static const struct iqs7211_event_desc iqs7211a_kp_events[] = { + { + .mask = BIT(14), + .reg_grp = IQS7211_REG_GRP_ALP, + }, + { + .name = "event-tap", + .mask = BIT(0), + .enable = BIT(0), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_TAP, + }, + { + .name = "event-hold", + .mask = BIT(1), + .enable = BIT(1), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_HOLD, + }, + { + .name = "event-swipe-x-neg", + .mask = BIT(2), + .enable = BIT(2), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_X, + }, + { + .name = "event-swipe-x-pos", + .mask = BIT(3), + .enable = BIT(3), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_X, + }, + { + .name = "event-swipe-y-pos", + .mask = BIT(4), + .enable = BIT(4), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_Y, + }, + { + .name = "event-swipe-y-neg", + .mask = BIT(5), + .enable = BIT(5), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_Y, + }, +}; + +static const struct iqs7211_event_desc iqs7211e_kp_events[] = { + { + .mask = BIT(14), + .reg_grp = IQS7211_REG_GRP_ALP, + }, + { + .name = "event-tap", + .mask = BIT(0), + .enable = BIT(0), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_TAP, + }, + { + .name = "event-tap-double", + .mask = BIT(1), + .enable = BIT(1), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_TAP, + }, + { + .name = "event-tap-triple", + .mask = BIT(2), + .enable = BIT(2), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_TAP, + }, + { + .name = "event-hold", + .mask = BIT(3), + .enable = BIT(3), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_HOLD, + }, + { + .name = "event-palm", + .mask = BIT(4), + .enable = BIT(4), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_PALM, + }, + { + .name = "event-swipe-x-pos", + .mask = BIT(8), + .enable = BIT(8), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_X, + }, + { + .name = "event-swipe-x-neg", + .mask = BIT(9), + .enable = BIT(9), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_X, + }, + { + .name = "event-swipe-y-pos", + .mask = BIT(10), + .enable = BIT(10), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_Y, + }, + { + .name = "event-swipe-y-neg", + .mask = BIT(11), + .enable = BIT(11), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_Y, + }, + { + .name = "event-swipe-x-pos-hold", + .mask = BIT(12), + .enable = BIT(12), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_HOLD, + }, + { + .name = "event-swipe-x-neg-hold", + .mask = BIT(13), + .enable = BIT(13), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_HOLD, + }, + { + .name = "event-swipe-y-pos-hold", + .mask = BIT(14), + .enable = BIT(14), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_HOLD, + }, + { + .name = "event-swipe-y-neg-hold", + .mask = BIT(15), + .enable = BIT(15), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_HOLD, + }, +}; + +struct iqs7211_dev_desc { + const char *tp_name; + const char *kp_name; + u16 prod_num; + u16 show_reset; + u16 ati_error[IQS7211_NUM_REG_GRPS]; + u16 ati_start[IQS7211_NUM_REG_GRPS]; + u16 suspend; + u16 ack_reset; + u16 comms_end; + u16 comms_req; + int charge_shift; + int info_offs; + int gesture_offs; + int contact_offs; + u8 sys_stat; + u8 sys_ctrl; + u8 alp_config; + u8 tp_config; + u8 exp_file; + u8 kp_enable[IQS7211_NUM_REG_GRPS]; + u8 gesture_angle; + u8 rx_tx_map; + u8 cycle_alloc[2]; + u8 cycle_limit[2]; + const struct iqs7211_event_desc *kp_events; + int num_kp_events; + int min_crx_alp; + int num_ctx; +}; + +static const struct iqs7211_dev_desc iqs7211_devs[] = { + [IQS7210A] = { + .tp_name = "iqs7210a_trackpad", + .kp_name = "iqs7210a_keys", + .prod_num = 944, + .show_reset = BIT(15), + .ati_error = { + [IQS7211_REG_GRP_TP] = BIT(12), + [IQS7211_REG_GRP_BTN] = BIT(0), + [IQS7211_REG_GRP_ALP] = BIT(8), + }, + .ati_start = { + [IQS7211_REG_GRP_TP] = BIT(13), + [IQS7211_REG_GRP_BTN] = BIT(1), + [IQS7211_REG_GRP_ALP] = BIT(9), + }, + .suspend = BIT(11), + .ack_reset = BIT(7), + .comms_end = BIT(2), + .comms_req = BIT(1), + .charge_shift = 4, + .info_offs = 0, + .gesture_offs = 1, + .contact_offs = 4, + .sys_stat = 0x0A, + .sys_ctrl = 0x35, + .alp_config = 0x39, + .tp_config = 0x4E, + .exp_file = 0x57, + .kp_enable = { + [IQS7211_REG_GRP_TP] = 0x58, + [IQS7211_REG_GRP_BTN] = 0x37, + [IQS7211_REG_GRP_ALP] = 0x37, + }, + .gesture_angle = 0x5F, + .rx_tx_map = 0x60, + .cycle_alloc = { 0x66, 0x75, }, + .cycle_limit = { 10, 6, }, + .kp_events = iqs7210a_kp_events, + .num_kp_events = ARRAY_SIZE(iqs7210a_kp_events), + .min_crx_alp = 4, + .num_ctx = IQS7211_MAX_CTX - 1, + }, + [IQS7211A] = { + .tp_name = "iqs7211a_trackpad", + .kp_name = "iqs7211a_keys", + .prod_num = 763, + .show_reset = BIT(7), + .ati_error = { + [IQS7211_REG_GRP_TP] = BIT(3), + [IQS7211_REG_GRP_ALP] = BIT(5), + }, + .ati_start = { + [IQS7211_REG_GRP_TP] = BIT(5), + [IQS7211_REG_GRP_ALP] = BIT(6), + }, + .ack_reset = BIT(7), + .comms_req = BIT(4), + .charge_shift = 0, + .info_offs = 0, + .gesture_offs = 1, + .contact_offs = 4, + .sys_stat = 0x10, + .sys_ctrl = 0x50, + .tp_config = 0x60, + .alp_config = 0x72, + .exp_file = 0x74, + .kp_enable = { + [IQS7211_REG_GRP_TP] = 0x80, + }, + .gesture_angle = 0x87, + .rx_tx_map = 0x90, + .cycle_alloc = { 0xA0, 0xB0, }, + .cycle_limit = { 10, 8, }, + .kp_events = iqs7211a_kp_events, + .num_kp_events = ARRAY_SIZE(iqs7211a_kp_events), + .num_ctx = IQS7211_MAX_CTX - 1, + }, + [IQS7211E] = { + .tp_name = "iqs7211e_trackpad", + .kp_name = "iqs7211e_keys", + .prod_num = 1112, + .show_reset = BIT(7), + .ati_error = { + [IQS7211_REG_GRP_TP] = BIT(3), + [IQS7211_REG_GRP_ALP] = BIT(5), + }, + .ati_start = { + [IQS7211_REG_GRP_TP] = BIT(5), + [IQS7211_REG_GRP_ALP] = BIT(6), + }, + .suspend = BIT(11), + .ack_reset = BIT(7), + .comms_end = BIT(6), + .comms_req = BIT(4), + .charge_shift = 0, + .info_offs = 1, + .gesture_offs = 0, + .contact_offs = 2, + .sys_stat = 0x0E, + .sys_ctrl = 0x33, + .tp_config = 0x41, + .alp_config = 0x36, + .exp_file = 0x4A, + .kp_enable = { + [IQS7211_REG_GRP_TP] = 0x4B, + }, + .gesture_angle = 0x55, + .rx_tx_map = 0x56, + .cycle_alloc = { 0x5D, 0x6C, }, + .cycle_limit = { 10, 11, }, + .kp_events = iqs7211e_kp_events, + .num_kp_events = ARRAY_SIZE(iqs7211e_kp_events), + .num_ctx = IQS7211_MAX_CTX, + }, +}; + +struct iqs7211_prop_desc { + const char *name; + enum iqs7211_reg_key_id reg_key; + u8 reg_addr[IQS7211_NUM_REG_GRPS][ARRAY_SIZE(iqs7211_devs)]; + int reg_shift; + int reg_width; + int val_pitch; + int val_min; + int val_max; + const char *label; +}; + +static const struct iqs7211_prop_desc iqs7211_props[] = { + { + .name = "azoteq,ati-frac-div-fine", + .reg_addr = { + [IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x1E, + [IQS7211A] = 0x30, + [IQS7211E] = 0x21, + }, + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x22, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x23, + [IQS7211A] = 0x36, + [IQS7211E] = 0x25, + }, + }, + .reg_shift = 9, + .reg_width = 5, + .label = "ATI fine fractional divider", + }, + { + .name = "azoteq,ati-frac-mult-coarse", + .reg_addr = { + [IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x1E, + [IQS7211A] = 0x30, + [IQS7211E] = 0x21, + }, + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x22, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x23, + [IQS7211A] = 0x36, + [IQS7211E] = 0x25, + }, + }, + .reg_shift = 5, + .reg_width = 4, + .label = "ATI coarse fractional multiplier", + }, + { + .name = "azoteq,ati-frac-div-coarse", + .reg_addr = { + [IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x1E, + [IQS7211A] = 0x30, + [IQS7211E] = 0x21, + }, + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x22, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x23, + [IQS7211A] = 0x36, + [IQS7211E] = 0x25, + }, + }, + .reg_shift = 0, + .reg_width = 5, + .label = "ATI coarse fractional divider", + }, + { + .name = "azoteq,ati-comp-div", + .reg_addr = { + [IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x1F, + [IQS7211E] = 0x22, + }, + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x24, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7211E] = 0x26, + }, + }, + .reg_shift = 0, + .reg_width = 8, + .val_max = 31, + .label = "ATI compensation divider", + }, + { + .name = "azoteq,ati-comp-div", + .reg_addr = { + [IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x24, + }, + }, + .reg_shift = 8, + .reg_width = 8, + .val_max = 31, + .label = "ATI compensation divider", + }, + { + .name = "azoteq,ati-comp-div", + .reg_addr = { + [IQS7211_REG_GRP_TP] = { + [IQS7211A] = 0x31, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7211A] = 0x37, + }, + }, + .val_max = 31, + .label = "ATI compensation divider", + }, + { + .name = "azoteq,ati-target", + .reg_addr = { + [IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x20, + [IQS7211A] = 0x32, + [IQS7211E] = 0x23, + }, + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x27, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x28, + [IQS7211A] = 0x38, + [IQS7211E] = 0x27, + }, + }, + .label = "ATI target", + }, + { + .name = "azoteq,ati-base", + .reg_addr[IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x26, + }, + .reg_shift = 8, + .reg_width = 8, + .val_pitch = 8, + .label = "ATI base", + }, + { + .name = "azoteq,ati-base", + .reg_addr[IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x26, + }, + .reg_shift = 0, + .reg_width = 8, + .val_pitch = 8, + .label = "ATI base", + }, + { + .name = "azoteq,rate-active-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x29, + [IQS7211A] = 0x40, + [IQS7211E] = 0x28, + }, + .label = "active mode report rate", + }, + { + .name = "azoteq,rate-touch-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x2A, + [IQS7211A] = 0x41, + [IQS7211E] = 0x29, + }, + .label = "idle-touch mode report rate", + }, + { + .name = "azoteq,rate-idle-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x2B, + [IQS7211A] = 0x42, + [IQS7211E] = 0x2A, + }, + .label = "idle mode report rate", + }, + { + .name = "azoteq,rate-lp1-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x2C, + [IQS7211A] = 0x43, + [IQS7211E] = 0x2B, + }, + .label = "low-power mode 1 report rate", + }, + { + .name = "azoteq,rate-lp2-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x2D, + [IQS7211A] = 0x44, + [IQS7211E] = 0x2C, + }, + .label = "low-power mode 2 report rate", + }, + { + .name = "azoteq,timeout-active-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x2E, + [IQS7211A] = 0x45, + [IQS7211E] = 0x2D, + }, + .val_pitch = 1000, + .label = "active mode timeout", + }, + { + .name = "azoteq,timeout-touch-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x2F, + [IQS7211A] = 0x46, + [IQS7211E] = 0x2E, + }, + .val_pitch = 1000, + .label = "idle-touch mode timeout", + }, + { + .name = "azoteq,timeout-idle-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x30, + [IQS7211A] = 0x47, + [IQS7211E] = 0x2F, + }, + .val_pitch = 1000, + .label = "idle mode timeout", + }, + { + .name = "azoteq,timeout-lp1-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x31, + [IQS7211A] = 0x48, + [IQS7211E] = 0x30, + }, + .val_pitch = 1000, + .label = "low-power mode 1 timeout", + }, + { + .name = "azoteq,timeout-lp2-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x32, + [IQS7211E] = 0x31, + }, + .reg_shift = 8, + .reg_width = 8, + .val_pitch = 1000, + .val_max = 60000, + .label = "trackpad reference value update rate", + }, + { + .name = "azoteq,timeout-lp2-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7211A] = 0x49, + }, + .val_pitch = 1000, + .val_max = 60000, + .label = "trackpad reference value update rate", + }, + { + .name = "azoteq,timeout-ati-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x32, + [IQS7211E] = 0x31, + }, + .reg_width = 8, + .val_pitch = 1000, + .val_max = 60000, + .label = "ATI error timeout", + }, + { + .name = "azoteq,timeout-ati-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7211A] = 0x35, + }, + .val_pitch = 1000, + .val_max = 60000, + .label = "ATI error timeout", + }, + { + .name = "azoteq,timeout-comms-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x33, + [IQS7211A] = 0x4A, + [IQS7211E] = 0x32, + }, + .label = "communication timeout", + }, + { + .name = "azoteq,timeout-press-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x34, + }, + .reg_width = 8, + .val_pitch = 1000, + .val_max = 60000, + .label = "press timeout", + }, + { + .name = "azoteq,ati-mode", + .reg_addr[IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x37, + }, + .reg_shift = 15, + .reg_width = 1, + .label = "ATI mode", + }, + { + .name = "azoteq,ati-mode", + .reg_addr[IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x37, + }, + .reg_shift = 7, + .reg_width = 1, + .label = "ATI mode", + }, + { + .name = "azoteq,sense-mode", + .reg_addr[IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x37, + [IQS7211A] = 0x72, + [IQS7211E] = 0x36, + }, + .reg_shift = 8, + .reg_width = 1, + .label = "sensing mode", + }, + { + .name = "azoteq,sense-mode", + .reg_addr[IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x37, + }, + .reg_shift = 0, + .reg_width = 2, + .val_max = 2, + .label = "sensing mode", + }, + { + .name = "azoteq,fosc-freq", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x38, + [IQS7211A] = 0x52, + [IQS7211E] = 0x35, + }, + .reg_shift = 4, + .reg_width = 1, + .label = "core clock frequency selection", + }, + { + .name = "azoteq,fosc-trim", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x38, + [IQS7211A] = 0x52, + [IQS7211E] = 0x35, + }, + .reg_shift = 0, + .reg_width = 4, + .label = "core clock frequency trim", + }, + { + .name = "azoteq,touch-exit", + .reg_addr = { + [IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x3B, + [IQS7211A] = 0x53, + [IQS7211E] = 0x38, + }, + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x3E, + }, + }, + .reg_shift = 8, + .reg_width = 8, + .label = "touch exit factor", + }, + { + .name = "azoteq,touch-enter", + .reg_addr = { + [IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x3B, + [IQS7211A] = 0x53, + [IQS7211E] = 0x38, + }, + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x3E, + }, + }, + .reg_shift = 0, + .reg_width = 8, + .label = "touch entrance factor", + }, + { + .name = "azoteq,thresh", + .reg_addr = { + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x3C, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x3D, + [IQS7211A] = 0x54, + [IQS7211E] = 0x39, + }, + }, + .label = "threshold", + }, + { + .name = "azoteq,debounce-exit", + .reg_addr = { + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x3F, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x40, + [IQS7211A] = 0x56, + [IQS7211E] = 0x3A, + }, + }, + .reg_shift = 8, + .reg_width = 8, + .label = "debounce exit factor", + }, + { + .name = "azoteq,debounce-enter", + .reg_addr = { + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x3F, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x40, + [IQS7211A] = 0x56, + [IQS7211E] = 0x3A, + }, + }, + .reg_shift = 0, + .reg_width = 8, + .label = "debounce entrance factor", + }, + { + .name = "azoteq,conv-frac", + .reg_addr = { + [IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x48, + [IQS7211A] = 0x58, + [IQS7211E] = 0x3D, + }, + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x49, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x4A, + [IQS7211A] = 0x59, + [IQS7211E] = 0x3E, + }, + }, + .reg_shift = 8, + .reg_width = 8, + .label = "conversion frequency fractional divider", + }, + { + .name = "azoteq,conv-period", + .reg_addr = { + [IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x48, + [IQS7211A] = 0x58, + [IQS7211E] = 0x3D, + }, + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x49, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x4A, + [IQS7211A] = 0x59, + [IQS7211E] = 0x3E, + }, + }, + .reg_shift = 0, + .reg_width = 8, + .label = "conversion period", + }, + { + .name = "azoteq,thresh", + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x55, + [IQS7211A] = 0x67, + [IQS7211E] = 0x48, + }, + .reg_shift = 0, + .reg_width = 8, + .label = "threshold", + }, + { + .name = "azoteq,contact-split", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x55, + [IQS7211A] = 0x67, + [IQS7211E] = 0x48, + }, + .reg_shift = 8, + .reg_width = 8, + .label = "contact split factor", + }, + { + .name = "azoteq,trim-x", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x56, + [IQS7211E] = 0x49, + }, + .reg_shift = 0, + .reg_width = 8, + .label = "horizontal trim width", + }, + { + .name = "azoteq,trim-x", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7211A] = 0x68, + }, + .label = "horizontal trim width", + }, + { + .name = "azoteq,trim-y", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x56, + [IQS7211E] = 0x49, + }, + .reg_shift = 8, + .reg_width = 8, + .label = "vertical trim height", + }, + { + .name = "azoteq,trim-y", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7211A] = 0x69, + }, + .label = "vertical trim height", + }, + { + .name = "azoteq,gesture-max-ms", + .reg_key = IQS7211_REG_KEY_TAP, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x59, + [IQS7211A] = 0x81, + [IQS7211E] = 0x4C, + }, + .label = "maximum gesture time", + }, + { + .name = "azoteq,gesture-mid-ms", + .reg_key = IQS7211_REG_KEY_TAP, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7211E] = 0x4D, + }, + .label = "repeated gesture time", + }, + { + .name = "azoteq,gesture-dist", + .reg_key = IQS7211_REG_KEY_TAP, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x5A, + [IQS7211A] = 0x82, + [IQS7211E] = 0x4E, + }, + .label = "gesture distance", + }, + { + .name = "azoteq,gesture-dist", + .reg_key = IQS7211_REG_KEY_HOLD, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x5A, + [IQS7211A] = 0x82, + [IQS7211E] = 0x4E, + }, + .label = "gesture distance", + }, + { + .name = "azoteq,gesture-min-ms", + .reg_key = IQS7211_REG_KEY_HOLD, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x5B, + [IQS7211A] = 0x83, + [IQS7211E] = 0x4F, + }, + .label = "minimum gesture time", + }, + { + .name = "azoteq,gesture-max-ms", + .reg_key = IQS7211_REG_KEY_AXIAL_X, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x5C, + [IQS7211A] = 0x84, + [IQS7211E] = 0x50, + }, + .label = "maximum gesture time", + }, + { + .name = "azoteq,gesture-max-ms", + .reg_key = IQS7211_REG_KEY_AXIAL_Y, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x5C, + [IQS7211A] = 0x84, + [IQS7211E] = 0x50, + }, + .label = "maximum gesture time", + }, + { + .name = "azoteq,gesture-dist", + .reg_key = IQS7211_REG_KEY_AXIAL_X, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x5D, + [IQS7211A] = 0x85, + [IQS7211E] = 0x51, + }, + .label = "gesture distance", + }, + { + .name = "azoteq,gesture-dist", + .reg_key = IQS7211_REG_KEY_AXIAL_Y, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x5E, + [IQS7211A] = 0x86, + [IQS7211E] = 0x52, + }, + .label = "gesture distance", + }, + { + .name = "azoteq,gesture-dist-rep", + .reg_key = IQS7211_REG_KEY_AXIAL_X, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7211E] = 0x53, + }, + .label = "repeated gesture distance", + }, + { + .name = "azoteq,gesture-dist-rep", + .reg_key = IQS7211_REG_KEY_AXIAL_Y, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7211E] = 0x54, + }, + .label = "repeated gesture distance", + }, + { + .name = "azoteq,thresh", + .reg_key = IQS7211_REG_KEY_PALM, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7211E] = 0x55, + }, + .reg_shift = 8, + .reg_width = 8, + .val_max = 42, + .label = "threshold", + }, +}; + +static const u8 iqs7211_gesture_angle[] = { + 0x00, 0x01, 0x02, 0x03, + 0x04, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, + 0x0E, 0x0F, 0x10, 0x11, + 0x12, 0x14, 0x15, 0x16, + 0x17, 0x19, 0x1A, 0x1B, + 0x1C, 0x1E, 0x1F, 0x21, + 0x22, 0x23, 0x25, 0x26, + 0x28, 0x2A, 0x2B, 0x2D, + 0x2E, 0x30, 0x32, 0x34, + 0x36, 0x38, 0x3A, 0x3C, + 0x3E, 0x40, 0x42, 0x45, + 0x47, 0x4A, 0x4C, 0x4F, + 0x52, 0x55, 0x58, 0x5B, + 0x5F, 0x63, 0x66, 0x6B, + 0x6F, 0x73, 0x78, 0x7E, + 0x83, 0x89, 0x90, 0x97, + 0x9E, 0xA7, 0xB0, 0xBA, + 0xC5, 0xD1, 0xDF, 0xEF, +}; + +struct iqs7211_ver_info { + __le16 prod_num; + __le16 major; + __le16 minor; + __le32 patch; +} __packed; + +struct iqs7211_touch_data { + __le16 abs_x; + __le16 abs_y; + __le16 pressure; + __le16 area; +} __packed; + +struct iqs7211_tp_config { + u8 tp_settings; + u8 total_rx; + u8 total_tx; + u8 num_contacts; + __le16 max_x; + __le16 max_y; +} __packed; + +struct iqs7211_private { + const struct iqs7211_dev_desc *dev_desc; + struct gpio_desc *reset_gpio; + struct gpio_desc *irq_gpio; + struct i2c_client *client; + struct input_dev *tp_idev; + struct input_dev *kp_idev; + struct iqs7211_ver_info ver_info; + struct iqs7211_tp_config tp_config; + struct touchscreen_properties prop; + struct list_head reg_field_head; + enum iqs7211_comms_mode comms_init; + enum iqs7211_comms_mode comms_mode; + unsigned int num_contacts; + unsigned int kp_code[ARRAY_SIZE(iqs7211e_kp_events)]; + u8 rx_tx_map[IQS7211_MAX_CTX + 1]; + u8 cycle_alloc[2][33]; + u8 exp_file[2]; + u16 event_mask; + u16 ati_start; + u16 gesture_cache; +}; + +static int iqs7211_irq_poll(struct iqs7211_private *iqs7211, u64 timeout_us) +{ + int error, val; + + error = readx_poll_timeout(gpiod_get_value_cansleep, iqs7211->irq_gpio, + val, val, IQS7211_COMMS_SLEEP_US, timeout_us); + + return val < 0 ? val : error; +} + +static int iqs7211_hard_reset(struct iqs7211_private *iqs7211) +{ + if (!iqs7211->reset_gpio) + return 0; + + gpiod_set_value_cansleep(iqs7211->reset_gpio, 1); + + /* + * The following delay ensures the shared RDY/MCLR pin is sampled in + * between periodic assertions by the device and assumes the default + * communication timeout has not been overwritten in OTP memory. + */ + if (iqs7211->reset_gpio == iqs7211->irq_gpio) + msleep(IQS7211_RESET_TIMEOUT_MS); + else + usleep_range(1000, 1100); + + gpiod_set_value_cansleep(iqs7211->reset_gpio, 0); + if (iqs7211->reset_gpio == iqs7211->irq_gpio) + iqs7211_irq_wait(); + + return iqs7211_irq_poll(iqs7211, IQS7211_START_TIMEOUT_US); +} + +static int iqs7211_force_comms(struct iqs7211_private *iqs7211) +{ + u8 msg_buf[] = { 0xFF, }; + int ret; + + switch (iqs7211->comms_mode) { + case IQS7211_COMMS_MODE_WAIT: + return iqs7211_irq_poll(iqs7211, IQS7211_START_TIMEOUT_US); + + case IQS7211_COMMS_MODE_FREE: + return 0; + + case IQS7211_COMMS_MODE_FORCE: + break; + + default: + return -EINVAL; + } + + /* + * The device cannot communicate until it asserts its interrupt (RDY) + * pin. Attempts to do so while RDY is deasserted return an ACK; how- + * ever all write data is ignored, and all read data returns 0xEE. + * + * Unsolicited communication must be preceded by a special force com- + * munication command, after which the device eventually asserts its + * RDY pin and agrees to communicate. + * + * Regardless of whether communication is forced or the result of an + * interrupt, the device automatically deasserts its RDY pin once it + * detects an I2C stop condition, or a timeout expires. + */ + ret = gpiod_get_value_cansleep(iqs7211->irq_gpio); + if (ret < 0) + return ret; + else if (ret > 0) + return 0; + + ret = i2c_master_send(iqs7211->client, msg_buf, sizeof(msg_buf)); + if (ret < (int)sizeof(msg_buf)) { + if (ret >= 0) + ret = -EIO; + + msleep(IQS7211_COMMS_RETRY_MS); + return ret; + } + + iqs7211_irq_wait(); + + return iqs7211_irq_poll(iqs7211, IQS7211_COMMS_TIMEOUT_US); +} + +static int iqs7211_read_burst(struct iqs7211_private *iqs7211, + u8 reg, void *val, u16 val_len) +{ + int ret, i; + struct i2c_client *client = iqs7211->client; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = sizeof(reg), + .buf = ®, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = val_len, + .buf = (u8 *)val, + }, + }; + + /* + * The following loop protects against an edge case in which the RDY + * pin is automatically deasserted just as the read is initiated. In + * that case, the read must be retried using forced communication. + */ + for (i = 0; i < IQS7211_NUM_RETRIES; i++) { + ret = iqs7211_force_comms(iqs7211); + if (ret < 0) + continue; + + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (ret < (int)ARRAY_SIZE(msg)) { + if (ret >= 0) + ret = -EIO; + + msleep(IQS7211_COMMS_RETRY_MS); + continue; + } + + if (get_unaligned_le16(msg[1].buf) == IQS7211_COMMS_ERROR) { + ret = -ENODATA; + continue; + } + + ret = 0; + break; + } + + iqs7211_irq_wait(); + + if (ret < 0) + dev_err(&client->dev, + "Failed to read from address 0x%02X: %d\n", reg, ret); + + return ret; +} + +static int iqs7211_read_word(struct iqs7211_private *iqs7211, u8 reg, u16 *val) +{ + __le16 val_buf; + int error; + + error = iqs7211_read_burst(iqs7211, reg, &val_buf, sizeof(val_buf)); + if (error) + return error; + + *val = le16_to_cpu(val_buf); + + return 0; +} + +static int iqs7211_write_burst(struct iqs7211_private *iqs7211, + u8 reg, const void *val, u16 val_len) +{ + int msg_len = sizeof(reg) + val_len; + int ret, i; + struct i2c_client *client = iqs7211->client; + u8 *msg_buf; + + msg_buf = kzalloc(msg_len, GFP_KERNEL); + if (!msg_buf) + return -ENOMEM; + + *msg_buf = reg; + memcpy(msg_buf + sizeof(reg), val, val_len); + + /* + * The following loop protects against an edge case in which the RDY + * pin is automatically asserted just before the force communication + * command is sent. + * + * In that case, the subsequent I2C stop condition tricks the device + * into preemptively deasserting the RDY pin and the command must be + * sent again. + */ + for (i = 0; i < IQS7211_NUM_RETRIES; i++) { + ret = iqs7211_force_comms(iqs7211); + if (ret < 0) + continue; + + ret = i2c_master_send(client, msg_buf, msg_len); + if (ret < msg_len) { + if (ret >= 0) + ret = -EIO; + + msleep(IQS7211_COMMS_RETRY_MS); + continue; + } + + ret = 0; + break; + } + + kfree(msg_buf); + + iqs7211_irq_wait(); + + if (ret < 0) + dev_err(&client->dev, + "Failed to write to address 0x%02X: %d\n", reg, ret); + + return ret; +} + +static int iqs7211_write_word(struct iqs7211_private *iqs7211, u8 reg, u16 val) +{ + __le16 val_buf = cpu_to_le16(val); + + return iqs7211_write_burst(iqs7211, reg, &val_buf, sizeof(val_buf)); +} + +static int iqs7211_start_comms(struct iqs7211_private *iqs7211) +{ + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + struct i2c_client *client = iqs7211->client; + bool forced_comms; + unsigned int val; + u16 comms_setup; + int error; + + /* + * Until forced communication can be enabled, the host must wait for a + * communication window each time it intends to elicit a response from + * the device. + * + * Forced communication is not necessary, however, if the host adapter + * can support clock stretching. In that case, the device freely clock + * stretches until all pending conversions are complete. + */ + forced_comms = device_property_present(&client->dev, + "azoteq,forced-comms"); + + error = device_property_read_u32(&client->dev, + "azoteq,forced-comms-default", &val); + if (error == -EINVAL) { + iqs7211->comms_init = IQS7211_COMMS_MODE_WAIT; + } else if (error) { + dev_err(&client->dev, + "Failed to read default communication mode: %d\n", + error); + return error; + } else if (val) { + iqs7211->comms_init = forced_comms ? IQS7211_COMMS_MODE_FORCE + : IQS7211_COMMS_MODE_WAIT; + } else { + iqs7211->comms_init = forced_comms ? IQS7211_COMMS_MODE_WAIT + : IQS7211_COMMS_MODE_FREE; + } + + iqs7211->comms_mode = iqs7211->comms_init; + + error = iqs7211_hard_reset(iqs7211); + if (error) { + dev_err(&client->dev, "Failed to reset device: %d\n", error); + return error; + } + + error = iqs7211_read_burst(iqs7211, IQS7211_PROD_NUM, + &iqs7211->ver_info, + sizeof(iqs7211->ver_info)); + if (error) + return error; + + if (le16_to_cpu(iqs7211->ver_info.prod_num) != dev_desc->prod_num) { + dev_err(&client->dev, "Invalid product number: %u\n", + le16_to_cpu(iqs7211->ver_info.prod_num)); + return -EINVAL; + } + + error = iqs7211_read_word(iqs7211, dev_desc->sys_ctrl + 1, + &comms_setup); + if (error) + return error; + + if (forced_comms) + comms_setup |= dev_desc->comms_req; + else + comms_setup &= ~dev_desc->comms_req; + + error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl + 1, + comms_setup | dev_desc->comms_end); + if (error) + return error; + + if (forced_comms) + iqs7211->comms_mode = IQS7211_COMMS_MODE_FORCE; + else + iqs7211->comms_mode = IQS7211_COMMS_MODE_FREE; + + error = iqs7211_read_burst(iqs7211, dev_desc->exp_file, + iqs7211->exp_file, + sizeof(iqs7211->exp_file)); + if (error) + return error; + + error = iqs7211_read_burst(iqs7211, dev_desc->tp_config, + &iqs7211->tp_config, + sizeof(iqs7211->tp_config)); + if (error) + return error; + + error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl + 1, + comms_setup); + if (error) + return error; + + iqs7211->event_mask = comms_setup & ~IQS7211_EVENT_MASK_ALL; + iqs7211->event_mask |= (IQS7211_EVENT_MASK_ATI | IQS7211_EVENT_MODE); + + return 0; +} + +static int iqs7211_init_device(struct iqs7211_private *iqs7211) +{ + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + struct iqs7211_reg_field_desc *reg_field; + __le16 sys_ctrl[] = { + cpu_to_le16(dev_desc->ack_reset), + cpu_to_le16(iqs7211->event_mask), + }; + int error, i; + + /* + * Acknowledge reset before writing any registers in case the device + * suffers a spurious reset during initialization. The communication + * mode is configured at this time as well. + */ + error = iqs7211_write_burst(iqs7211, dev_desc->sys_ctrl, sys_ctrl, + sizeof(sys_ctrl)); + if (error) + return error; + + if (iqs7211->event_mask & dev_desc->comms_req) + iqs7211->comms_mode = IQS7211_COMMS_MODE_FORCE; + else + iqs7211->comms_mode = IQS7211_COMMS_MODE_FREE; + + /* + * Take advantage of the stop-bit disable function, if available, to + * save the trouble of having to reopen a communication window after + * each read or write. + */ + error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl + 1, + iqs7211->event_mask | dev_desc->comms_end); + if (error) + return error; + + list_for_each_entry(reg_field, &iqs7211->reg_field_head, list) { + u16 new_val = reg_field->val; + + if (reg_field->mask < U16_MAX) { + u16 old_val; + + error = iqs7211_read_word(iqs7211, reg_field->addr, + &old_val); + if (error) + return error; + + new_val = old_val & ~reg_field->mask; + new_val |= reg_field->val; + + if (new_val == old_val) + continue; + } + + error = iqs7211_write_word(iqs7211, reg_field->addr, new_val); + if (error) + return error; + } + + error = iqs7211_write_burst(iqs7211, dev_desc->tp_config, + &iqs7211->tp_config, + sizeof(iqs7211->tp_config)); + if (error) + return error; + + if (**iqs7211->cycle_alloc) { + error = iqs7211_write_burst(iqs7211, dev_desc->rx_tx_map, + &iqs7211->rx_tx_map, + dev_desc->num_ctx); + if (error) + return error; + + for (i = 0; i < sizeof(dev_desc->cycle_limit); i++) { + error = iqs7211_write_burst(iqs7211, + dev_desc->cycle_alloc[i], + iqs7211->cycle_alloc[i], + dev_desc->cycle_limit[i] * 3); + if (error) + return error; + } + } + + *sys_ctrl = cpu_to_le16(iqs7211->ati_start); + + return iqs7211_write_burst(iqs7211, dev_desc->sys_ctrl, sys_ctrl, + sizeof(sys_ctrl)); +} + +static int iqs7211_add_field(struct iqs7211_private *iqs7211, + struct iqs7211_reg_field_desc new_field) +{ + struct i2c_client *client = iqs7211->client; + struct iqs7211_reg_field_desc *reg_field; + + if (!new_field.addr) + return 0; + + list_for_each_entry(reg_field, &iqs7211->reg_field_head, list) { + if (reg_field->addr != new_field.addr) + continue; + + reg_field->mask |= new_field.mask; + reg_field->val |= new_field.val; + return 0; + } + + reg_field = devm_kzalloc(&client->dev, sizeof(*reg_field), GFP_KERNEL); + if (!reg_field) + return -ENOMEM; + + reg_field->addr = new_field.addr; + reg_field->mask = new_field.mask; + reg_field->val = new_field.val; + + list_add(®_field->list, &iqs7211->reg_field_head); + + return 0; +} + +static int iqs7211_parse_props(struct iqs7211_private *iqs7211, + struct fwnode_handle *reg_grp_node, + enum iqs7211_reg_grp_id reg_grp, + enum iqs7211_reg_key_id reg_key) +{ + struct i2c_client *client = iqs7211->client; + int i; + + for (i = 0; i < ARRAY_SIZE(iqs7211_props); i++) { + const char *name = iqs7211_props[i].name; + u8 reg_addr = iqs7211_props[i].reg_addr[reg_grp] + [iqs7211->dev_desc - + iqs7211_devs]; + int reg_shift = iqs7211_props[i].reg_shift; + int reg_width = iqs7211_props[i].reg_width ? : 16; + int val_pitch = iqs7211_props[i].val_pitch ? : 1; + int val_min = iqs7211_props[i].val_min; + int val_max = iqs7211_props[i].val_max; + const char *label = iqs7211_props[i].label ? : name; + struct iqs7211_reg_field_desc reg_field; + unsigned int val; + int error; + + if (iqs7211_props[i].reg_key != reg_key) + continue; + + if (!reg_addr) + continue; + + error = fwnode_property_read_u32(reg_grp_node, name, &val); + if (error == -EINVAL) { + continue; + } else if (error) { + dev_err(&client->dev, "Failed to read %s %s: %d\n", + fwnode_get_name(reg_grp_node), label, error); + return error; + } + + if (!val_max) + val_max = GENMASK(reg_width - 1, 0) * val_pitch; + + if (val < val_min || val > val_max) { + dev_err(&client->dev, "Invalid %s: %u\n", label, val); + return -EINVAL; + } + + reg_field.addr = reg_addr; + reg_field.mask = GENMASK(reg_shift + reg_width - 1, reg_shift); + reg_field.val = val / val_pitch << reg_shift; + + error = iqs7211_add_field(iqs7211, reg_field); + if (error) + return error; + } + + return 0; +} + +static int iqs7211_parse_event(struct iqs7211_private *iqs7211, + struct fwnode_handle *event_node, + enum iqs7211_reg_grp_id reg_grp, + enum iqs7211_reg_key_id reg_key, + unsigned int *event_code) +{ + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + struct i2c_client *client = iqs7211->client; + struct iqs7211_reg_field_desc reg_field; + unsigned int val; + int error; + + error = iqs7211_parse_props(iqs7211, event_node, reg_grp, reg_key); + if (error) + return error; + + if (reg_key == IQS7211_REG_KEY_AXIAL_X || + reg_key == IQS7211_REG_KEY_AXIAL_Y) { + error = fwnode_property_read_u32(event_node, + "azoteq,gesture-angle", &val); + if (!error) { + if (val >= ARRAY_SIZE(iqs7211_gesture_angle)) { + dev_err(&client->dev, + "Invalid %s gesture angle: %u\n", + fwnode_get_name(event_node), val); + return -EINVAL; + } + + reg_field.addr = dev_desc->gesture_angle; + reg_field.mask = U8_MAX; + reg_field.val = iqs7211_gesture_angle[val]; + + error = iqs7211_add_field(iqs7211, reg_field); + if (error) + return error; + } else if (error != -EINVAL) { + dev_err(&client->dev, + "Failed to read %s gesture angle: %d\n", + fwnode_get_name(event_node), error); + return error; + } + } + + error = fwnode_property_read_u32(event_node, "linux,code", event_code); + if (error == -EINVAL) + error = 0; + else if (error) + dev_err(&client->dev, "Failed to read %s code: %d\n", + fwnode_get_name(event_node), error); + + return error; +} + +static int iqs7211_parse_cycles(struct iqs7211_private *iqs7211, + struct fwnode_handle *tp_node) +{ + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + struct i2c_client *client = iqs7211->client; + int num_cycles = dev_desc->cycle_limit[0] + dev_desc->cycle_limit[1]; + int error, count, i, j, k, cycle_start; + unsigned int cycle_alloc[IQS7211_MAX_CYCLES][2]; + u8 total_rx = iqs7211->tp_config.total_rx; + u8 total_tx = iqs7211->tp_config.total_tx; + + for (i = 0; i < IQS7211_MAX_CYCLES * 2; i++) + *(cycle_alloc[0] + i) = U8_MAX; + + count = fwnode_property_count_u32(tp_node, "azoteq,channel-select"); + if (count == -EINVAL) { + /* + * Assign each sensing cycle's slots (0 and 1) to a channel, + * defined as the intersection between two CRx and CTx pins. + * A channel assignment of 255 means the slot is unused. + */ + for (i = 0, cycle_start = 0; i < total_tx; i++) { + int cycle_stop = 0; + + for (j = 0; j < total_rx; j++) { + /* + * Channels formed by CRx0-3 and CRx4-7 are + * bound to slots 0 and 1, respectively. + */ + int slot = iqs7211->rx_tx_map[j] < 4 ? 0 : 1; + int chan = i * total_rx + j; + + for (k = cycle_start; k < num_cycles; k++) { + if (cycle_alloc[k][slot] < U8_MAX) + continue; + + cycle_alloc[k][slot] = chan; + break; + } + + if (k < num_cycles) { + cycle_stop = max(k, cycle_stop); + continue; + } + + dev_err(&client->dev, + "Insufficient number of cycles\n"); + return -EINVAL; + } + + /* + * Sensing cycles cannot straddle more than one CTx + * pin. As such, the next row's starting cycle must + * be greater than the previous row's highest cycle. + */ + cycle_start = cycle_stop + 1; + } + } else if (count < 0) { + dev_err(&client->dev, "Failed to count channels: %d\n", count); + return count; + } else if (count > num_cycles * 2) { + dev_err(&client->dev, "Insufficient number of cycles\n"); + return -EINVAL; + } else if (count > 0) { + error = fwnode_property_read_u32_array(tp_node, + "azoteq,channel-select", + cycle_alloc[0], count); + if (error) { + dev_err(&client->dev, "Failed to read channels: %d\n", + error); + return error; + } + + for (i = 0; i < count; i++) { + int chan = *(cycle_alloc[0] + i); + + if (chan == U8_MAX) + continue; + + if (chan >= total_rx * total_tx) { + dev_err(&client->dev, "Invalid channel: %d\n", + chan); + return -EINVAL; + } + + for (j = 0; j < count; j++) { + if (j == i || *(cycle_alloc[0] + j) != chan) + continue; + + dev_err(&client->dev, "Duplicate channel: %d\n", + chan); + return -EINVAL; + } + } + } + + /* + * Once the raw channel assignments have been derived, they must be + * packed according to the device's register map. + */ + for (i = 0, cycle_start = 0; i < sizeof(dev_desc->cycle_limit); i++) { + int offs = 0; + + for (j = cycle_start; + j < cycle_start + dev_desc->cycle_limit[i]; j++) { + iqs7211->cycle_alloc[i][offs++] = 0x05; + iqs7211->cycle_alloc[i][offs++] = cycle_alloc[j][0]; + iqs7211->cycle_alloc[i][offs++] = cycle_alloc[j][1]; + } + + cycle_start += dev_desc->cycle_limit[i]; + } + + return 0; +} + +static int iqs7211_parse_tp(struct iqs7211_private *iqs7211, + struct fwnode_handle *tp_node) +{ + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + struct i2c_client *client = iqs7211->client; + unsigned int pins[IQS7211_MAX_CTX]; + int error, count, i, j; + + count = fwnode_property_count_u32(tp_node, "azoteq,rx-enable"); + if (count == -EINVAL) { + return 0; + } else if (count < 0) { + dev_err(&client->dev, "Failed to count CRx pins: %d\n", count); + return count; + } else if (count > IQS7211_NUM_CRX) { + dev_err(&client->dev, "Invalid number of CRx pins\n"); + return -EINVAL; + } + + error = fwnode_property_read_u32_array(tp_node, "azoteq,rx-enable", + pins, count); + if (error) { + dev_err(&client->dev, "Failed to read CRx pins: %d\n", error); + return error; + } + + for (i = 0; i < count; i++) { + if (pins[i] >= IQS7211_NUM_CRX) { + dev_err(&client->dev, "Invalid CRx pin: %u\n", pins[i]); + return -EINVAL; + } + + iqs7211->rx_tx_map[i] = pins[i]; + } + + iqs7211->tp_config.total_rx = count; + + count = fwnode_property_count_u32(tp_node, "azoteq,tx-enable"); + if (count < 0) { + dev_err(&client->dev, "Failed to count CTx pins: %d\n", count); + return count; + } else if (count > dev_desc->num_ctx) { + dev_err(&client->dev, "Invalid number of CTx pins\n"); + return -EINVAL; + } + + error = fwnode_property_read_u32_array(tp_node, "azoteq,tx-enable", + pins, count); + if (error) { + dev_err(&client->dev, "Failed to read CTx pins: %d\n", error); + return error; + } + + for (i = 0; i < count; i++) { + if (pins[i] >= dev_desc->num_ctx) { + dev_err(&client->dev, "Invalid CTx pin: %u\n", pins[i]); + return -EINVAL; + } + + for (j = 0; j < iqs7211->tp_config.total_rx; j++) { + if (iqs7211->rx_tx_map[j] != pins[i]) + continue; + + dev_err(&client->dev, "Conflicting CTx pin: %u\n", + pins[i]); + return -EINVAL; + } + + iqs7211->rx_tx_map[iqs7211->tp_config.total_rx + i] = pins[i]; + } + + iqs7211->tp_config.total_tx = count; + + return iqs7211_parse_cycles(iqs7211, tp_node); +} + +static int iqs7211_parse_alp(struct iqs7211_private *iqs7211, + struct fwnode_handle *alp_node) +{ + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + struct i2c_client *client = iqs7211->client; + struct iqs7211_reg_field_desc reg_field; + int error, count, i; + + count = fwnode_property_count_u32(alp_node, "azoteq,rx-enable"); + if (count < 0 && count != -EINVAL) { + dev_err(&client->dev, "Failed to count CRx pins: %d\n", count); + return count; + } else if (count > IQS7211_NUM_CRX) { + dev_err(&client->dev, "Invalid number of CRx pins\n"); + return -EINVAL; + } else if (count >= 0) { + unsigned int pins[IQS7211_NUM_CRX]; + + error = fwnode_property_read_u32_array(alp_node, + "azoteq,rx-enable", + pins, count); + if (error) { + dev_err(&client->dev, "Failed to read CRx pins: %d\n", + error); + return error; + } + + reg_field.addr = dev_desc->alp_config; + reg_field.mask = GENMASK(IQS7211_NUM_CRX - 1, 0); + reg_field.val = 0; + + for (i = 0; i < count; i++) { + if (pins[i] < dev_desc->min_crx_alp || + pins[i] >= IQS7211_NUM_CRX) { + dev_err(&client->dev, "Invalid CRx pin: %u\n", + pins[i]); + return -EINVAL; + } + + reg_field.val |= BIT(pins[i]); + } + + error = iqs7211_add_field(iqs7211, reg_field); + if (error) + return error; + } + + count = fwnode_property_count_u32(alp_node, "azoteq,tx-enable"); + if (count < 0 && count != -EINVAL) { + dev_err(&client->dev, "Failed to count CTx pins: %d\n", count); + return count; + } else if (count > dev_desc->num_ctx) { + dev_err(&client->dev, "Invalid number of CTx pins\n"); + return -EINVAL; + } else if (count >= 0) { + unsigned int pins[IQS7211_MAX_CTX]; + + error = fwnode_property_read_u32_array(alp_node, + "azoteq,tx-enable", + pins, count); + if (error) { + dev_err(&client->dev, "Failed to read CTx pins: %d\n", + error); + return error; + } + + reg_field.addr = dev_desc->alp_config + 1; + reg_field.mask = GENMASK(dev_desc->num_ctx - 1, 0); + reg_field.val = 0; + + for (i = 0; i < count; i++) { + if (pins[i] >= dev_desc->num_ctx) { + dev_err(&client->dev, "Invalid CTx pin: %u\n", + pins[i]); + return -EINVAL; + } + + reg_field.val |= BIT(pins[i]); + } + + error = iqs7211_add_field(iqs7211, reg_field); + if (error) + return error; + } + + return 0; +} + +static int (*iqs7211_parse_extra[IQS7211_NUM_REG_GRPS]) + (struct iqs7211_private *iqs7211, + struct fwnode_handle *reg_grp_node) = { + [IQS7211_REG_GRP_TP] = iqs7211_parse_tp, + [IQS7211_REG_GRP_ALP] = iqs7211_parse_alp, +}; + +static int iqs7211_parse_reg_grp(struct iqs7211_private *iqs7211, + struct fwnode_handle *reg_grp_node, + enum iqs7211_reg_grp_id reg_grp) +{ + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + struct iqs7211_reg_field_desc reg_field; + int error, i; + + error = iqs7211_parse_props(iqs7211, reg_grp_node, reg_grp, + IQS7211_REG_KEY_NONE); + if (error) + return error; + + if (iqs7211_parse_extra[reg_grp]) { + error = iqs7211_parse_extra[reg_grp](iqs7211, reg_grp_node); + if (error) + return error; + } + + iqs7211->ati_start |= dev_desc->ati_start[reg_grp]; + + reg_field.addr = dev_desc->kp_enable[reg_grp]; + reg_field.mask = 0; + reg_field.val = 0; + + for (i = 0; i < dev_desc->num_kp_events; i++) { + const char *event_name = dev_desc->kp_events[i].name; + struct fwnode_handle *event_node; + + if (dev_desc->kp_events[i].reg_grp != reg_grp) + continue; + + reg_field.mask |= dev_desc->kp_events[i].enable; + + if (event_name) + event_node = fwnode_get_named_child_node(reg_grp_node, + event_name); + else + event_node = fwnode_handle_get(reg_grp_node); + + if (!event_node) + continue; + + error = iqs7211_parse_event(iqs7211, event_node, + dev_desc->kp_events[i].reg_grp, + dev_desc->kp_events[i].reg_key, + &iqs7211->kp_code[i]); + fwnode_handle_put(event_node); + if (error) + return error; + + reg_field.val |= dev_desc->kp_events[i].enable; + + iqs7211->event_mask |= iqs7211_reg_grp_masks[reg_grp]; + } + + return iqs7211_add_field(iqs7211, reg_field); +} + +static int iqs7211_register_kp(struct iqs7211_private *iqs7211) +{ + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + struct input_dev *kp_idev = iqs7211->kp_idev; + struct i2c_client *client = iqs7211->client; + int error, i; + + for (i = 0; i < dev_desc->num_kp_events; i++) + if (iqs7211->kp_code[i]) + break; + + if (i == dev_desc->num_kp_events) + return 0; + + kp_idev = devm_input_allocate_device(&client->dev); + if (!kp_idev) + return -ENOMEM; + + iqs7211->kp_idev = kp_idev; + + kp_idev->name = dev_desc->kp_name; + kp_idev->id.bustype = BUS_I2C; + + for (i = 0; i < dev_desc->num_kp_events; i++) + if (iqs7211->kp_code[i]) + input_set_capability(iqs7211->kp_idev, EV_KEY, + iqs7211->kp_code[i]); + + error = input_register_device(kp_idev); + if (error) + dev_err(&client->dev, "Failed to register %s: %d\n", + kp_idev->name, error); + + return error; +} + +static int iqs7211_register_tp(struct iqs7211_private *iqs7211) +{ + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + struct touchscreen_properties *prop = &iqs7211->prop; + struct input_dev *tp_idev = iqs7211->tp_idev; + struct i2c_client *client = iqs7211->client; + int error; + + error = device_property_read_u32(&client->dev, "azoteq,num-contacts", + &iqs7211->num_contacts); + if (error == -EINVAL) { + return 0; + } else if (error) { + dev_err(&client->dev, "Failed to read number of contacts: %d\n", + error); + return error; + } else if (iqs7211->num_contacts > IQS7211_MAX_CONTACTS) { + dev_err(&client->dev, "Invalid number of contacts: %u\n", + iqs7211->num_contacts); + return -EINVAL; + } + + iqs7211->tp_config.num_contacts = iqs7211->num_contacts ? : 1; + + if (!iqs7211->num_contacts) + return 0; + + iqs7211->event_mask |= IQS7211_EVENT_MASK_MOVE; + + tp_idev = devm_input_allocate_device(&client->dev); + if (!tp_idev) + return -ENOMEM; + + iqs7211->tp_idev = tp_idev; + + tp_idev->name = dev_desc->tp_name; + tp_idev->id.bustype = BUS_I2C; + + input_set_abs_params(tp_idev, ABS_MT_POSITION_X, + 0, le16_to_cpu(iqs7211->tp_config.max_x), 0, 0); + + input_set_abs_params(tp_idev, ABS_MT_POSITION_Y, + 0, le16_to_cpu(iqs7211->tp_config.max_y), 0, 0); + + input_set_abs_params(tp_idev, ABS_MT_PRESSURE, 0, U16_MAX, 0, 0); + + touchscreen_parse_properties(tp_idev, true, prop); + + /* + * The device reserves 0xFFFF for coordinates that correspond to slots + * which are not in a state of touch. + */ + if (prop->max_x >= U16_MAX || prop->max_y >= U16_MAX) { + dev_err(&client->dev, "Invalid trackpad size: %u*%u\n", + prop->max_x, prop->max_y); + return -EINVAL; + } + + iqs7211->tp_config.max_x = cpu_to_le16(prop->max_x); + iqs7211->tp_config.max_y = cpu_to_le16(prop->max_y); + + error = input_mt_init_slots(tp_idev, iqs7211->num_contacts, + INPUT_MT_DIRECT); + if (error) { + dev_err(&client->dev, "Failed to initialize slots: %d\n", + error); + return error; + } + + error = input_register_device(tp_idev); + if (error) + dev_err(&client->dev, "Failed to register %s: %d\n", + tp_idev->name, error); + + return error; +} + +static int iqs7211_report(struct iqs7211_private *iqs7211) +{ + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + struct i2c_client *client = iqs7211->client; + struct iqs7211_touch_data *touch_data; + u16 info_flags, charge_mode, gesture_flags; + __le16 status[12]; + int error, i; + + error = iqs7211_read_burst(iqs7211, dev_desc->sys_stat, status, + dev_desc->contact_offs * sizeof(__le16) + + iqs7211->num_contacts * sizeof(*touch_data)); + if (error) + return error; + + info_flags = le16_to_cpu(status[dev_desc->info_offs]); + + if (info_flags & dev_desc->show_reset) { + dev_err(&client->dev, "Unexpected device reset\n"); + + /* + * The device may or may not expect forced communication after + * it exits hardware reset, so the corresponding state machine + * must be reset as well. + */ + iqs7211->comms_mode = iqs7211->comms_init; + + return iqs7211_init_device(iqs7211); + } + + for (i = 0; i < ARRAY_SIZE(dev_desc->ati_error); i++) { + if (!(info_flags & dev_desc->ati_error[i])) + continue; + + dev_err(&client->dev, "Unexpected %s ATI error\n", + iqs7211_reg_grp_names[i]); + return 0; + } + + for (i = 0; i < iqs7211->num_contacts; i++) { + u16 pressure; + + touch_data = (struct iqs7211_touch_data *) + &status[dev_desc->contact_offs] + i; + pressure = le16_to_cpu(touch_data->pressure); + + input_mt_slot(iqs7211->tp_idev, i); + if (input_mt_report_slot_state(iqs7211->tp_idev, MT_TOOL_FINGER, + pressure != 0)) { + touchscreen_report_pos(iqs7211->tp_idev, &iqs7211->prop, + le16_to_cpu(touch_data->abs_x), + le16_to_cpu(touch_data->abs_y), + true); + input_report_abs(iqs7211->tp_idev, ABS_MT_PRESSURE, + pressure); + } + } + + if (iqs7211->num_contacts) { + input_mt_sync_frame(iqs7211->tp_idev); + input_sync(iqs7211->tp_idev); + } + + if (!iqs7211->kp_idev) + return 0; + + charge_mode = info_flags & GENMASK(dev_desc->charge_shift + 2, + dev_desc->charge_shift); + charge_mode >>= dev_desc->charge_shift; + + /* + * A charging mode higher than 2 (idle mode) indicates the device last + * operated in low-power mode and intends to express an ALP event. + */ + if (info_flags & dev_desc->kp_events->mask && charge_mode > 2) { + input_report_key(iqs7211->kp_idev, *iqs7211->kp_code, 1); + input_sync(iqs7211->kp_idev); + + input_report_key(iqs7211->kp_idev, *iqs7211->kp_code, 0); + } + + for (i = 0; i < dev_desc->num_kp_events; i++) { + if (dev_desc->kp_events[i].reg_grp != IQS7211_REG_GRP_BTN) + continue; + + input_report_key(iqs7211->kp_idev, iqs7211->kp_code[i], + info_flags & dev_desc->kp_events[i].mask); + } + + gesture_flags = le16_to_cpu(status[dev_desc->gesture_offs]); + + for (i = 0; i < dev_desc->num_kp_events; i++) { + enum iqs7211_reg_key_id reg_key = dev_desc->kp_events[i].reg_key; + u16 mask = dev_desc->kp_events[i].mask; + + if (dev_desc->kp_events[i].reg_grp != IQS7211_REG_GRP_TP) + continue; + + if ((gesture_flags ^ iqs7211->gesture_cache) & mask) + input_report_key(iqs7211->kp_idev, iqs7211->kp_code[i], + gesture_flags & mask); + + iqs7211->gesture_cache &= ~mask; + + /* + * Hold and palm gestures persist while the contact remains in + * place; all others are momentary and hence are followed by a + * complementary release event. + */ + if (reg_key == IQS7211_REG_KEY_HOLD || + reg_key == IQS7211_REG_KEY_PALM) { + iqs7211->gesture_cache |= gesture_flags & mask; + gesture_flags &= ~mask; + } + } + + if (gesture_flags) { + input_sync(iqs7211->kp_idev); + + for (i = 0; i < dev_desc->num_kp_events; i++) + if (dev_desc->kp_events[i].reg_grp == IQS7211_REG_GRP_TP && + gesture_flags & dev_desc->kp_events[i].mask) + input_report_key(iqs7211->kp_idev, + iqs7211->kp_code[i], 0); + } + + input_sync(iqs7211->kp_idev); + + return 0; +} + +static irqreturn_t iqs7211_irq(int irq, void *context) +{ + struct iqs7211_private *iqs7211 = context; + + return iqs7211_report(iqs7211) ? IRQ_NONE : IRQ_HANDLED; +} + +static int iqs7211_suspend(struct device *dev) +{ + struct iqs7211_private *iqs7211 = dev_get_drvdata(dev); + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + int error; + + if (!dev_desc->suspend || device_may_wakeup(dev)) + return 0; + + /* + * I2C communication prompts the device to assert its RDY pin if it is + * not already asserted. As such, the interrupt must be disabled so as + * to prevent reentrant interrupts. + */ + disable_irq(gpiod_to_irq(iqs7211->irq_gpio)); + + error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl, + dev_desc->suspend); + + enable_irq(gpiod_to_irq(iqs7211->irq_gpio)); + + return error; +} + +static int iqs7211_resume(struct device *dev) +{ + struct iqs7211_private *iqs7211 = dev_get_drvdata(dev); + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + __le16 sys_ctrl[] = { + 0, + cpu_to_le16(iqs7211->event_mask), + }; + int error; + + if (!dev_desc->suspend || device_may_wakeup(dev)) + return 0; + + disable_irq(gpiod_to_irq(iqs7211->irq_gpio)); + + /* + * Forced communication, if in use, must be explicitly enabled as part + * of the wake-up command. + */ + error = iqs7211_write_burst(iqs7211, dev_desc->sys_ctrl, sys_ctrl, + sizeof(sys_ctrl)); + + enable_irq(gpiod_to_irq(iqs7211->irq_gpio)); + + return error; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(iqs7211_pm, iqs7211_suspend, iqs7211_resume); + +static ssize_t fw_info_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iqs7211_private *iqs7211 = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%u.%u.%u.%u:%u.%u\n", + le16_to_cpu(iqs7211->ver_info.prod_num), + le32_to_cpu(iqs7211->ver_info.patch), + le16_to_cpu(iqs7211->ver_info.major), + le16_to_cpu(iqs7211->ver_info.minor), + iqs7211->exp_file[1], iqs7211->exp_file[0]); +} + +static DEVICE_ATTR_RO(fw_info); + +static struct attribute *iqs7211_attrs[] = { + &dev_attr_fw_info.attr, + NULL +}; +ATTRIBUTE_GROUPS(iqs7211); + +static const struct of_device_id iqs7211_of_match[] = { + { + .compatible = "azoteq,iqs7210a", + .data = (void *)IQS7210A, + }, + { + .compatible = "azoteq,iqs7211a", + .data = (void *)IQS7211A, + }, + { + .compatible = "azoteq,iqs7211e", + .data = (void *)IQS7211E, + }, + { } +}; +MODULE_DEVICE_TABLE(of, iqs7211_of_match); + +static const struct i2c_device_id iqs7211_id[] = { + { "iqs7210a", IQS7210A }, + { "iqs7211a", IQS7211A }, + { "iqs7211e", IQS7211E }, + { } +}; +MODULE_DEVICE_TABLE(i2c, iqs7211_id); + +static int iqs7211_probe(struct i2c_client *client) +{ + struct iqs7211_private *iqs7211; + enum iqs7211_reg_grp_id reg_grp; + enum iqs7211_dev_id dev_id; + unsigned long irq_flags; + bool shared_irq; + int error, irq; + + iqs7211 = devm_kzalloc(&client->dev, sizeof(*iqs7211), GFP_KERNEL); + if (!iqs7211) + return -ENOMEM; + + i2c_set_clientdata(client, iqs7211); + iqs7211->client = client; + + INIT_LIST_HEAD(&iqs7211->reg_field_head); + + if (client->dev.of_node) + dev_id = (enum iqs7211_dev_id)of_device_get_match_data(&client->dev); + else + dev_id = i2c_match_id(iqs7211_id, client)->driver_data; + + shared_irq = iqs7211_devs[dev_id].num_ctx == IQS7211_MAX_CTX; + iqs7211->dev_desc = &iqs7211_devs[dev_id]; + + /* + * The RDY pin behaves as an interrupt, but must also be polled ahead + * of unsolicited I2C communication. As such, it is first opened as a + * GPIO and then passed to gpiod_to_irq() to register the interrupt. + * + * If an extra CTx pin is present, the RDY and MCLR pins are combined + * into a single bidirectional pin. In that case, the platform's GPIO + * must be configured as an open-drain output. + */ + iqs7211->irq_gpio = devm_gpiod_get(&client->dev, "irq", + shared_irq ? GPIOD_OUT_LOW + : GPIOD_IN); + if (IS_ERR(iqs7211->irq_gpio)) { + error = PTR_ERR(iqs7211->irq_gpio); + dev_err(&client->dev, "Failed to request IRQ GPIO: %d\n", + error); + return error; + } + + if (shared_irq) { + iqs7211->reset_gpio = iqs7211->irq_gpio; + } else { + iqs7211->reset_gpio = devm_gpiod_get_optional(&client->dev, + "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(iqs7211->reset_gpio)) { + error = PTR_ERR(iqs7211->reset_gpio); + dev_err(&client->dev, + "Failed to request reset GPIO: %d\n", error); + return error; + } + } + + error = iqs7211_start_comms(iqs7211); + if (error) + return error; + + for (reg_grp = 0; reg_grp < IQS7211_NUM_REG_GRPS; reg_grp++) { + const char *reg_grp_name = iqs7211_reg_grp_names[reg_grp]; + struct fwnode_handle *reg_grp_node; + + if (reg_grp_name) + reg_grp_node = device_get_named_child_node(&client->dev, + reg_grp_name); + else + reg_grp_node = fwnode_handle_get(dev_fwnode(&client->dev)); + + if (!reg_grp_node) + continue; + + error = iqs7211_parse_reg_grp(iqs7211, reg_grp_node, reg_grp); + fwnode_handle_put(reg_grp_node); + if (error) + return error; + } + + error = iqs7211_register_kp(iqs7211); + if (error) + return error; + + error = iqs7211_register_tp(iqs7211); + if (error) + return error; + + error = iqs7211_init_device(iqs7211); + if (error) + return error; + + irq = gpiod_to_irq(iqs7211->irq_gpio); + if (irq < 0) + return irq; + + irq_flags = gpiod_is_active_low(iqs7211->irq_gpio) ? IRQF_TRIGGER_LOW + : IRQF_TRIGGER_HIGH; + irq_flags |= IRQF_ONESHOT; + + error = devm_request_threaded_irq(&client->dev, irq, NULL, iqs7211_irq, + irq_flags, client->name, iqs7211); + if (error) + dev_err(&client->dev, "Failed to request IRQ: %d\n", error); + + return error; +} + +static struct i2c_driver iqs7211_i2c_driver = { + .probe = iqs7211_probe, + .id_table = iqs7211_id, + .driver = { + .name = "iqs7211", + .of_match_table = iqs7211_of_match, + .dev_groups = iqs7211_groups, + .pm = pm_sleep_ptr(&iqs7211_pm), + }, +}; +module_i2c_driver(iqs7211_i2c_driver); + +MODULE_AUTHOR("Jeff LaBundy "); +MODULE_DESCRIPTION("Azoteq IQS7210A/7211A/E Trackpad/Touchscreen Controller"); +MODULE_LICENSE("GPL"); -- GitLab From cfc2928cb213d5c20b6313abb2d603c0c60d7637 Mon Sep 17 00:00:00 2001 From: Amit Kumar Mahapatra Date: Fri, 30 Jun 2023 19:52:32 +0530 Subject: [PATCH 0176/3445] dt-bindings: mtd: jedec, spi-nor: Add DT property to avoid setting SRWD bit in status register If the WP# signal of the flash device is either not connected or is wrongly tied to GND (that includes internal pull-downs), and the software sets the status register write disable (SRWD) bit in the status register then the status register permanently becomes read-only. To avoid this added a new boolean DT property "no-wp". If this property is set in the DT then the software avoids setting the SRWD during status register write operation. Signed-off-by: Amit Kumar Mahapatra Reviewed-by: Conor Dooley Reviewed-by: Rob Herring Reviewed-by: Michael Walle Link: https://lore.kernel.org/r/20230630142233.63585-2-amit.kumar-mahapatra@amd.com Signed-off-by: Tudor Ambarus --- .../devicetree/bindings/mtd/jedec,spi-nor.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml index 89959e5c47bae..97344969b02d4 100644 --- a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml +++ b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml @@ -70,6 +70,21 @@ properties: be used on such systems, to denote the absence of a reliable reset mechanism. + no-wp: + type: boolean + description: + The status register write disable (SRWD) bit in status register, combined + with the WP# signal, provides hardware data protection for the device. When + the SRWD bit is set to 1, and the WP# signal is either driven LOW or hard + strapped to LOW, the status register nonvolatile bits become read-only and + the WRITE STATUS REGISTER operation will not execute. The only way to exit + this hardware-protected mode is to drive WP# HIGH. If the WP# signal of the + flash device is not connected or is wrongly tied to GND (that includes internal + pull-downs) then status register permanently becomes read-only as the SRWD bit + cannot be reset. This boolean flag can be used on such systems to avoid setting + the SRWD bit while writing the status register. WP# signal hard strapped to GND + can be a valid use case. + reset-gpios: description: A GPIO line connected to the RESET (active low) signal of the device. -- GitLab From 18d7d01a0a0eb32b78149c8259bf49504d5fa4e0 Mon Sep 17 00:00:00 2001 From: Amit Kumar Mahapatra Date: Fri, 30 Jun 2023 19:52:33 +0530 Subject: [PATCH 0177/3445] mtd: spi-nor: Avoid setting SRWD bit in SR if WP# signal not connected Setting the status register write disable (SRWD) bit in the status register (SR) with WP# signal of the flash left floating or wrongly tied to GND (that includes internal pull-downs), will configure the SR permanently as read-only. If WP# signal is left floating or wrongly tied to GND, avoid setting SRWD bit while writing the SR during flash protection. Signed-off-by: Amit Kumar Mahapatra Reviewed-by: Michael Walle Link: https://lore.kernel.org/r/20230630142233.63585-3-amit.kumar-mahapatra@amd.com Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.c | 3 +++ drivers/mtd/spi-nor/core.h | 1 + drivers/mtd/spi-nor/debugfs.c | 1 + drivers/mtd/spi-nor/swp.c | 9 +++++++-- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 5f29fac8669a3..434c545c0ce40 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -2844,6 +2844,9 @@ static void spi_nor_init_flags(struct spi_nor *nor) if (of_property_read_bool(np, "broken-flash-reset")) nor->flags |= SNOR_F_BROKEN_RESET; + if (of_property_read_bool(np, "no-wp")) + nor->flags |= SNOR_F_NO_WP; + if (flags & SPI_NOR_SWP_IS_VOLATILE) nor->flags |= SNOR_F_SWP_IS_VOLATILE; diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index 4fb5ff09c63a9..55b5e7abce6eb 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -132,6 +132,7 @@ enum spi_nor_option_flags { SNOR_F_SWP_IS_VOLATILE = BIT(13), SNOR_F_RWW = BIT(14), SNOR_F_ECC = BIT(15), + SNOR_F_NO_WP = BIT(16), }; struct spi_nor_read_command { diff --git a/drivers/mtd/spi-nor/debugfs.c b/drivers/mtd/spi-nor/debugfs.c index e11536fffe0f4..6e163cb5b478c 100644 --- a/drivers/mtd/spi-nor/debugfs.c +++ b/drivers/mtd/spi-nor/debugfs.c @@ -27,6 +27,7 @@ static const char *const snor_f_names[] = { SNOR_F_NAME(SWP_IS_VOLATILE), SNOR_F_NAME(RWW), SNOR_F_NAME(ECC), + SNOR_F_NAME(NO_WP), }; #undef SNOR_F_NAME diff --git a/drivers/mtd/spi-nor/swp.c b/drivers/mtd/spi-nor/swp.c index 0ba716e84377f..5ab9d53248608 100644 --- a/drivers/mtd/spi-nor/swp.c +++ b/drivers/mtd/spi-nor/swp.c @@ -214,8 +214,13 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) status_new = (status_old & ~mask & ~tb_mask) | val; - /* Disallow further writes if WP pin is asserted */ - status_new |= SR_SRWD; + /* + * Disallow further writes if WP# pin is neither left floating nor + * wrongly tied to GND (that includes internal pull-downs). + * WP# pin hard strapped to GND can be a valid use case. + */ + if (!(nor->flags & SNOR_F_NO_WP)) + status_new |= SR_SRWD; if (!use_top) status_new |= tb_mask; -- GitLab From 4b0cb4e7ab2f777c0dd07b6d381047db85801a89 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 16 Jun 2023 16:00:54 +0200 Subject: [PATCH 0178/3445] dt-bindings: mtd: spi-nor: clarify the need for spi-nor compatibles Most SPI NOR devices do not require a specific compatible, their ID can in general be discovered with the JEDEC READ ID opcode. In this case, only the "jedec,spi-nor" generic compatible is expected. Clarify this information in the compatible description to (i) help device-tree writers and (ii) prevent further attempts to extend this list with useless information. Signed-off-by: Miquel Raynal Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230616140054.2788684-1-miquel.raynal@bootlin.com [ta: s/JEDEC/JEDEC SFDP for clarity and s/JEDEC READ ID/READ ID as the opcode is not part of the JEDEC SFDP standard.] Signed-off-by: Tudor Ambarus --- Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml index 97344969b02d4..58f0cea160ef5 100644 --- a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml +++ b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml @@ -43,8 +43,10 @@ properties: - const: jedec,spi-nor - const: jedec,spi-nor description: - Must also include "jedec,spi-nor" for any SPI NOR flash that can be - identified by the JEDEC READ ID opcode (0x9F). + SPI NOR flashes compatible with the JEDEC SFDP standard or which may be + identified with the READ ID opcode (0x9F) do not deserve a specific + compatible. They should instead only be matched against the generic + "jedec,spi-nor" compatible. reg: minItems: 1 -- GitLab From 56f99cdc5b11a65a19410171b6a84c612778f0c9 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 30 Jun 2023 18:58:28 +0200 Subject: [PATCH 0179/3445] clocksource/drivers/timer-oxnas-rps: Remove obsolete timer driver Due to lack of maintenance and stall of development for a few years now, and since no new features will ever be added upstream, remove support for OX810 and OX820 timer. Acked-by: Linus Walleij Acked-by: Arnd Bergmann Acked-by: Daniel Golle Signed-off-by: Neil Armstrong Acked-by: Andy Shevchenko Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230630-topic-oxnas-upstream-remove-v2-3-fb6ab3dea87c@linaro.org --- drivers/clocksource/Kconfig | 7 - drivers/clocksource/Makefile | 1 - drivers/clocksource/timer-oxnas-rps.c | 288 -------------------------- 3 files changed, 296 deletions(-) delete mode 100644 drivers/clocksource/timer-oxnas-rps.c diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index c4d671a5a13d9..0ba0dc4ecf062 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -461,13 +461,6 @@ config VF_PIT_TIMER help Support for Periodic Interrupt Timer on Freescale Vybrid Family SoCs. -config OXNAS_RPS_TIMER - bool "Oxford Semiconductor OXNAS RPS Timers driver" if COMPILE_TEST - select TIMER_OF - select CLKSRC_MMIO - help - This enables support for the Oxford Semiconductor OXNAS RPS timers. - config SYS_SUPPORTS_SH_CMT bool diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 5d93c9e3fc558..368c3461dab81 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -54,7 +54,6 @@ obj-$(CONFIG_MTK_TIMER) += timer-mediatek.o obj-$(CONFIG_MTK_CPUX_TIMER) += timer-mediatek-cpux.o obj-$(CONFIG_CLKSRC_PISTACHIO) += timer-pistachio.o obj-$(CONFIG_CLKSRC_TI_32K) += timer-ti-32k.o -obj-$(CONFIG_OXNAS_RPS_TIMER) += timer-oxnas-rps.o obj-$(CONFIG_OWL_TIMER) += timer-owl.o obj-$(CONFIG_MILBEAUT_TIMER) += timer-milbeaut.o obj-$(CONFIG_SPRD_TIMER) += timer-sprd.o diff --git a/drivers/clocksource/timer-oxnas-rps.c b/drivers/clocksource/timer-oxnas-rps.c deleted file mode 100644 index d514b44e67dd1..0000000000000 --- a/drivers/clocksource/timer-oxnas-rps.c +++ /dev/null @@ -1,288 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * drivers/clocksource/timer-oxnas-rps.c - * - * Copyright (C) 2009 Oxford Semiconductor Ltd - * Copyright (C) 2013 Ma Haijun - * Copyright (C) 2016 Neil Armstrong - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* TIMER1 used as tick - * TIMER2 used as clocksource - */ - -/* Registers definitions */ - -#define TIMER_LOAD_REG 0x0 -#define TIMER_CURR_REG 0x4 -#define TIMER_CTRL_REG 0x8 -#define TIMER_CLRINT_REG 0xC - -#define TIMER_BITS 24 - -#define TIMER_MAX_VAL (BIT(TIMER_BITS) - 1) - -#define TIMER_PERIODIC BIT(6) -#define TIMER_ENABLE BIT(7) - -#define TIMER_DIV1 (0) -#define TIMER_DIV16 (1 << 2) -#define TIMER_DIV256 (2 << 2) - -#define TIMER1_REG_OFFSET 0 -#define TIMER2_REG_OFFSET 0x20 - -/* Clockevent & Clocksource data */ - -struct oxnas_rps_timer { - struct clock_event_device clkevent; - void __iomem *clksrc_base; - void __iomem *clkevt_base; - unsigned long timer_period; - unsigned int timer_prescaler; - struct clk *clk; - int irq; -}; - -static irqreturn_t oxnas_rps_timer_irq(int irq, void *dev_id) -{ - struct oxnas_rps_timer *rps = dev_id; - - writel_relaxed(0, rps->clkevt_base + TIMER_CLRINT_REG); - - rps->clkevent.event_handler(&rps->clkevent); - - return IRQ_HANDLED; -} - -static void oxnas_rps_timer_config(struct oxnas_rps_timer *rps, - unsigned long period, - unsigned int periodic) -{ - uint32_t cfg = rps->timer_prescaler; - - if (period) - cfg |= TIMER_ENABLE; - - if (periodic) - cfg |= TIMER_PERIODIC; - - writel_relaxed(period, rps->clkevt_base + TIMER_LOAD_REG); - writel_relaxed(cfg, rps->clkevt_base + TIMER_CTRL_REG); -} - -static int oxnas_rps_timer_shutdown(struct clock_event_device *evt) -{ - struct oxnas_rps_timer *rps = - container_of(evt, struct oxnas_rps_timer, clkevent); - - oxnas_rps_timer_config(rps, 0, 0); - - return 0; -} - -static int oxnas_rps_timer_set_periodic(struct clock_event_device *evt) -{ - struct oxnas_rps_timer *rps = - container_of(evt, struct oxnas_rps_timer, clkevent); - - oxnas_rps_timer_config(rps, rps->timer_period, 1); - - return 0; -} - -static int oxnas_rps_timer_set_oneshot(struct clock_event_device *evt) -{ - struct oxnas_rps_timer *rps = - container_of(evt, struct oxnas_rps_timer, clkevent); - - oxnas_rps_timer_config(rps, rps->timer_period, 0); - - return 0; -} - -static int oxnas_rps_timer_next_event(unsigned long delta, - struct clock_event_device *evt) -{ - struct oxnas_rps_timer *rps = - container_of(evt, struct oxnas_rps_timer, clkevent); - - oxnas_rps_timer_config(rps, delta, 0); - - return 0; -} - -static int __init oxnas_rps_clockevent_init(struct oxnas_rps_timer *rps) -{ - ulong clk_rate = clk_get_rate(rps->clk); - ulong timer_rate; - - /* Start with prescaler 1 */ - rps->timer_prescaler = TIMER_DIV1; - rps->timer_period = DIV_ROUND_UP(clk_rate, HZ); - timer_rate = clk_rate; - - if (rps->timer_period > TIMER_MAX_VAL) { - rps->timer_prescaler = TIMER_DIV16; - timer_rate = clk_rate / 16; - rps->timer_period = DIV_ROUND_UP(timer_rate, HZ); - } - if (rps->timer_period > TIMER_MAX_VAL) { - rps->timer_prescaler = TIMER_DIV256; - timer_rate = clk_rate / 256; - rps->timer_period = DIV_ROUND_UP(timer_rate, HZ); - } - - rps->clkevent.name = "oxnas-rps"; - rps->clkevent.features = CLOCK_EVT_FEAT_PERIODIC | - CLOCK_EVT_FEAT_ONESHOT | - CLOCK_EVT_FEAT_DYNIRQ; - rps->clkevent.tick_resume = oxnas_rps_timer_shutdown; - rps->clkevent.set_state_shutdown = oxnas_rps_timer_shutdown; - rps->clkevent.set_state_periodic = oxnas_rps_timer_set_periodic; - rps->clkevent.set_state_oneshot = oxnas_rps_timer_set_oneshot; - rps->clkevent.set_next_event = oxnas_rps_timer_next_event; - rps->clkevent.rating = 200; - rps->clkevent.cpumask = cpu_possible_mask; - rps->clkevent.irq = rps->irq; - clockevents_config_and_register(&rps->clkevent, - timer_rate, - 1, - TIMER_MAX_VAL); - - pr_info("Registered clock event rate %luHz prescaler %x period %lu\n", - clk_rate, - rps->timer_prescaler, - rps->timer_period); - - return 0; -} - -/* Clocksource */ - -static void __iomem *timer_sched_base; - -static u64 notrace oxnas_rps_read_sched_clock(void) -{ - return ~readl_relaxed(timer_sched_base); -} - -static int __init oxnas_rps_clocksource_init(struct oxnas_rps_timer *rps) -{ - ulong clk_rate = clk_get_rate(rps->clk); - int ret; - - /* use prescale 16 */ - clk_rate = clk_rate / 16; - - writel_relaxed(TIMER_MAX_VAL, rps->clksrc_base + TIMER_LOAD_REG); - writel_relaxed(TIMER_PERIODIC | TIMER_ENABLE | TIMER_DIV16, - rps->clksrc_base + TIMER_CTRL_REG); - - timer_sched_base = rps->clksrc_base + TIMER_CURR_REG; - sched_clock_register(oxnas_rps_read_sched_clock, - TIMER_BITS, clk_rate); - ret = clocksource_mmio_init(timer_sched_base, - "oxnas_rps_clocksource_timer", - clk_rate, 250, TIMER_BITS, - clocksource_mmio_readl_down); - if (WARN_ON(ret)) { - pr_err("can't register clocksource\n"); - return ret; - } - - pr_info("Registered clocksource rate %luHz\n", clk_rate); - - return 0; -} - -static int __init oxnas_rps_timer_init(struct device_node *np) -{ - struct oxnas_rps_timer *rps; - void __iomem *base; - int ret; - - rps = kzalloc(sizeof(*rps), GFP_KERNEL); - if (!rps) - return -ENOMEM; - - rps->clk = of_clk_get(np, 0); - if (IS_ERR(rps->clk)) { - ret = PTR_ERR(rps->clk); - goto err_alloc; - } - - ret = clk_prepare_enable(rps->clk); - if (ret) - goto err_clk; - - base = of_iomap(np, 0); - if (!base) { - ret = -ENXIO; - goto err_clk_prepare; - } - - rps->irq = irq_of_parse_and_map(np, 0); - if (!rps->irq) { - ret = -EINVAL; - goto err_iomap; - } - - rps->clkevt_base = base + TIMER1_REG_OFFSET; - rps->clksrc_base = base + TIMER2_REG_OFFSET; - - /* Disable timers */ - writel_relaxed(0, rps->clkevt_base + TIMER_CTRL_REG); - writel_relaxed(0, rps->clksrc_base + TIMER_CTRL_REG); - writel_relaxed(0, rps->clkevt_base + TIMER_LOAD_REG); - writel_relaxed(0, rps->clksrc_base + TIMER_LOAD_REG); - writel_relaxed(0, rps->clkevt_base + TIMER_CLRINT_REG); - writel_relaxed(0, rps->clksrc_base + TIMER_CLRINT_REG); - - ret = request_irq(rps->irq, oxnas_rps_timer_irq, - IRQF_TIMER | IRQF_IRQPOLL, - "rps-timer", rps); - if (ret) - goto err_iomap; - - ret = oxnas_rps_clocksource_init(rps); - if (ret) - goto err_irqreq; - - ret = oxnas_rps_clockevent_init(rps); - if (ret) - goto err_irqreq; - - return 0; - -err_irqreq: - free_irq(rps->irq, rps); -err_iomap: - iounmap(base); -err_clk_prepare: - clk_disable_unprepare(rps->clk); -err_clk: - clk_put(rps->clk); -err_alloc: - kfree(rps); - - return ret; -} - -TIMER_OF_DECLARE(ox810se_rps, - "oxsemi,ox810se-rps-timer", oxnas_rps_timer_init); -TIMER_OF_DECLARE(ox820_rps, - "oxsemi,ox820-rps-timer", oxnas_rps_timer_init); -- GitLab From c42b7a385286a99024ed2e6c2566929083b49ec8 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 30 Jun 2023 18:58:29 +0200 Subject: [PATCH 0180/3445] dt-bindings: timer: oxsemi,rps-timer: remove obsolete bindings Due to lack of maintenance and stall of development for a few years now, and since no new features will ever be added upstream, remove the OX810 and OX820 timer bindings. Acked-by: Krzysztof Kozlowski Acked-by: Linus Walleij Acked-by: Arnd Bergmann Acked-by: Daniel Golle Signed-off-by: Neil Armstrong Acked-by: Andy Shevchenko Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230630-topic-oxnas-upstream-remove-v2-4-fb6ab3dea87c@linaro.org --- .../bindings/timer/oxsemi,rps-timer.txt | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 Documentation/devicetree/bindings/timer/oxsemi,rps-timer.txt diff --git a/Documentation/devicetree/bindings/timer/oxsemi,rps-timer.txt b/Documentation/devicetree/bindings/timer/oxsemi,rps-timer.txt deleted file mode 100644 index d191612539e88..0000000000000 --- a/Documentation/devicetree/bindings/timer/oxsemi,rps-timer.txt +++ /dev/null @@ -1,17 +0,0 @@ -Oxford Semiconductor OXNAS SoCs Family RPS Timer -================================================ - -Required properties: -- compatible: Should be "oxsemi,ox810se-rps-timer" or "oxsemi,ox820-rps-timer" -- reg : Specifies base physical address and size of the registers. -- interrupts : The interrupts of the two timers -- clocks : The phandle of the timer clock source - -example: - -timer0: timer@200 { - compatible = "oxsemi,ox810se-rps-timer"; - reg = <0x200 0x40>; - clocks = <&rpsclk>; - interrupts = <4 5>; -}; -- GitLab From 677232f879f2464007c511a73048ff5996b479fc Mon Sep 17 00:00:00 2001 From: Jeff LaBundy Date: Thu, 13 Jul 2023 13:12:02 -0500 Subject: [PATCH 0181/3445] Input: iqs7211 - point to match data directly Point the OF match table directly to the struct that describes the device as opposed to an intermediate enum; doing so simplifies the code and avoids a clang warning. As part of this change, the I2C device ID table is removed, as the device cannot probe without an OF node due to the unique nature of the hardware's interrupt pin. Fixes: f2ba47e65f3b ("Input: add support for Azoteq IQS7210A/7211A/E") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202307131717.LtwApG0z-lkp@intel.com/ Signed-off-by: Jeff LaBundy Link: https://lore.kernel.org/r/ZLA+cuciIeVcCvm6@nixie71 Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/iqs7211.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/drivers/input/touchscreen/iqs7211.c b/drivers/input/touchscreen/iqs7211.c index f60316d37f454..dc084f8737620 100644 --- a/drivers/input/touchscreen/iqs7211.c +++ b/drivers/input/touchscreen/iqs7211.c @@ -2420,33 +2420,24 @@ ATTRIBUTE_GROUPS(iqs7211); static const struct of_device_id iqs7211_of_match[] = { { .compatible = "azoteq,iqs7210a", - .data = (void *)IQS7210A, + .data = &iqs7211_devs[IQS7210A], }, { .compatible = "azoteq,iqs7211a", - .data = (void *)IQS7211A, + .data = &iqs7211_devs[IQS7211A], }, { .compatible = "azoteq,iqs7211e", - .data = (void *)IQS7211E, + .data = &iqs7211_devs[IQS7211E], }, { } }; MODULE_DEVICE_TABLE(of, iqs7211_of_match); -static const struct i2c_device_id iqs7211_id[] = { - { "iqs7210a", IQS7210A }, - { "iqs7211a", IQS7211A }, - { "iqs7211e", IQS7211E }, - { } -}; -MODULE_DEVICE_TABLE(i2c, iqs7211_id); - static int iqs7211_probe(struct i2c_client *client) { struct iqs7211_private *iqs7211; enum iqs7211_reg_grp_id reg_grp; - enum iqs7211_dev_id dev_id; unsigned long irq_flags; bool shared_irq; int error, irq; @@ -2460,13 +2451,11 @@ static int iqs7211_probe(struct i2c_client *client) INIT_LIST_HEAD(&iqs7211->reg_field_head); - if (client->dev.of_node) - dev_id = (enum iqs7211_dev_id)of_device_get_match_data(&client->dev); - else - dev_id = i2c_match_id(iqs7211_id, client)->driver_data; + iqs7211->dev_desc = device_get_match_data(&client->dev); + if (!iqs7211->dev_desc) + return -ENODEV; - shared_irq = iqs7211_devs[dev_id].num_ctx == IQS7211_MAX_CTX; - iqs7211->dev_desc = &iqs7211_devs[dev_id]; + shared_irq = iqs7211->dev_desc->num_ctx == IQS7211_MAX_CTX; /* * The RDY pin behaves as an interrupt, but must also be polled ahead @@ -2554,7 +2543,6 @@ static int iqs7211_probe(struct i2c_client *client) static struct i2c_driver iqs7211_i2c_driver = { .probe = iqs7211_probe, - .id_table = iqs7211_id, .driver = { .name = "iqs7211", .of_match_table = iqs7211_of_match, -- GitLab From cd47fe860185a8d385bba693ab79497fdf12cd78 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Wed, 5 Jul 2023 22:14:34 +0900 Subject: [PATCH 0182/3445] MAINTAINERS: adjust printk/vsprintf entries M should be earned. Signed-off-by: Sergey Senozhatsky Signed-off-by: Petr Mladek Link: https://lore.kernel.org/r/20230705131511.2806776-1-senozhatsky@chromium.org --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index cec07c796296b..8cb807526d744 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16807,9 +16807,9 @@ F: kernel/sched/psi.c PRINTK M: Petr Mladek -M: Sergey Senozhatsky R: Steven Rostedt R: John Ogness +R: Sergey Senozhatsky S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux.git F: include/linux/printk.h @@ -22413,9 +22413,9 @@ F: drivers/net/vrf.c VSPRINTF M: Petr Mladek M: Steven Rostedt -M: Sergey Senozhatsky R: Andy Shevchenko R: Rasmus Villemoes +R: Sergey Senozhatsky S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux.git F: Documentation/core-api/printk-formats.rst -- GitLab From 1fdfa7cccd35519d97a1f301b8143ea4196b2d16 Mon Sep 17 00:00:00 2001 From: Andrew Davis Date: Thu, 13 Jul 2023 15:09:57 -0500 Subject: [PATCH 0183/3445] phy: ti: gmii-sel: Allow parent to not be syscon node If the parent node is not a syscon type, then fallback and check if we can get a regmap from our own node. This no longer forces us to make the parent of this node a syscon node when that might not be appropriate. Signed-off-by: Andrew Davis Reviewed-by: Roger Quadros Reviewed-by: Siddharth Vadapalli Link: https://lore.kernel.org/r/20230713200957.134480-1-afd@ti.com Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-gmii-sel.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c index 6286cf25a4264..555b323f45da1 100644 --- a/drivers/phy/ti/phy-gmii-sel.c +++ b/drivers/phy/ti/phy-gmii-sel.c @@ -465,9 +465,12 @@ static int phy_gmii_sel_probe(struct platform_device *pdev) priv->regmap = syscon_node_to_regmap(node->parent); if (IS_ERR(priv->regmap)) { - ret = PTR_ERR(priv->regmap); - dev_err(dev, "Failed to get syscon %d\n", ret); - return ret; + priv->regmap = device_node_to_regmap(node); + if (IS_ERR(priv->regmap)) { + ret = PTR_ERR(priv->regmap); + dev_err(dev, "Failed to get syscon %d\n", ret); + return ret; + } } ret = phy_gmii_sel_init_ports(priv); -- GitLab From 6eb4da8cf54537992fc9843be8b2af4f83f717e0 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 5 Jun 2023 21:59:39 -0300 Subject: [PATCH 0184/3445] iommu: Have __iommu_probe_device() check for already probed devices This is a step toward making __iommu_probe_device() self contained. It should, under proper locking, check if the device is already associated with an iommu driver and resolve parallel probes. All but one of the callers open code this test using two different means, but they all rely on dev->iommu_group. Currently the bus_iommu_probe()/probe_iommu_group() and probe_acpi_namespace_devices() rejects already probed devices with an unlocked read of dev->iommu_group. The OF and ACPI "replay" functions use device_iommu_mapped() which is the same read without the pointless refcount. Move this test into __iommu_probe_device() and put it under the iommu_probe_device_lock. The store to dev->iommu_group is in iommu_group_add_device() which is also called under this lock for iommu driver devices, making it properly locked. The only path that didn't have this check is the hotplug path triggered by BUS_NOTIFY_ADD_DEVICE. The only way to get dev->iommu_group assigned outside the probe path is via iommu_group_add_device(). Today the only caller is VFIO no-iommu which never associates with an iommu driver. Thus adding this additional check is safe. Reviewed-by: Kevin Tian Reviewed-by: Lu Baolu Acked-by: Rafael J. Wysocki Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/1-v3-328044aa278c+45e49-iommu_probe_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/acpi/scan.c | 2 +- drivers/iommu/intel/iommu.c | 7 ------- drivers/iommu/iommu.c | 19 +++++++++---------- drivers/iommu/of_iommu.c | 2 +- 4 files changed, 11 insertions(+), 19 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 5b145f1aaa1b8..daa64dd687524 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1581,7 +1581,7 @@ static const struct iommu_ops *acpi_iommu_configure_id(struct device *dev, * If we have reason to believe the IOMMU driver missed the initial * iommu_probe_device() call for dev, replay it to get things in order. */ - if (!err && dev->bus && !device_iommu_mapped(dev)) + if (!err && dev->bus) err = iommu_probe_device(dev); /* Ignore all other errors apart from EPROBE_DEFER */ diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index 5c8c5cdc36cf5..d5ca2387e65c6 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -3756,7 +3756,6 @@ static int __init probe_acpi_namespace_devices(void) for_each_active_dev_scope(drhd->devices, drhd->devices_cnt, i, dev) { struct acpi_device_physical_node *pn; - struct iommu_group *group; struct acpi_device *adev; if (dev->bus != &acpi_bus_type) @@ -3766,12 +3765,6 @@ static int __init probe_acpi_namespace_devices(void) mutex_lock(&adev->physical_node_lock); list_for_each_entry(pn, &adev->physical_node_list, node) { - group = iommu_group_get(pn->dev); - if (group) { - iommu_group_put(group); - continue; - } - ret = iommu_probe_device(pn->dev); if (ret) break; diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index da340f11c5f5b..bdc5ce884b7bf 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -351,9 +351,16 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list * but for now enforcing a simple global ordering is fine. */ mutex_lock(&iommu_probe_device_lock); + + /* Device is probed already if in a group */ + if (dev->iommu_group) { + ret = 0; + goto out_unlock; + } + if (!dev_iommu_get(dev)) { ret = -ENOMEM; - goto err_unlock; + goto out_unlock; } if (!try_module_get(ops->owner)) { @@ -399,7 +406,7 @@ out_module_put: err_free: dev_iommu_free(dev); -err_unlock: +out_unlock: mutex_unlock(&iommu_probe_device_lock); return ret; @@ -1711,16 +1718,8 @@ struct iommu_domain *iommu_group_default_domain(struct iommu_group *group) static int probe_iommu_group(struct device *dev, void *data) { struct list_head *group_list = data; - struct iommu_group *group; int ret; - /* Device is probed already if in a group */ - group = iommu_group_get(dev); - if (group) { - iommu_group_put(group); - return 0; - } - ret = __iommu_probe_device(dev, group_list); if (ret == -ENODEV) ret = 0; diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c index 40f57d293a79d..157b286e36bf3 100644 --- a/drivers/iommu/of_iommu.c +++ b/drivers/iommu/of_iommu.c @@ -159,7 +159,7 @@ const struct iommu_ops *of_iommu_configure(struct device *dev, * If we have reason to believe the IOMMU driver missed the initial * probe for dev, replay it to get things in order. */ - if (!err && dev->bus && !device_iommu_mapped(dev)) + if (!err && dev->bus) err = iommu_probe_device(dev); /* Ignore all other errors apart from EPROBE_DEFER */ -- GitLab From 5665d15d3cb796d363a2dc0d2ed17855a3cb5942 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 5 Jun 2023 21:59:40 -0300 Subject: [PATCH 0185/3445] iommu: Use iommu_group_ref_get/put() for dev->iommu_group No reason to open code this, use the proper helper functions. Reviewed-by: Kevin Tian Reviewed-by: Lu Baolu Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/2-v3-328044aa278c+45e49-iommu_probe_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index bdc5ce884b7bf..2f16f988ab363 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -500,7 +500,7 @@ static void __iommu_group_release_device(struct iommu_group *group, kfree(grp_dev->name); kfree(grp_dev); dev->iommu_group = NULL; - kobject_put(group->devices_kobj); + iommu_group_put(group); } static void iommu_release_device(struct device *dev) @@ -1067,8 +1067,7 @@ rename: goto err_free_name; } - kobject_get(group->devices_kobj); - + iommu_group_ref_get(group); dev->iommu_group = group; mutex_lock(&group->mutex); -- GitLab From 7bdb99622f7e7dcaa58bfc2fa98caf23cfc40994 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 5 Jun 2023 21:59:41 -0300 Subject: [PATCH 0186/3445] iommu: Inline iommu_group_get_for_dev() into __iommu_probe_device() This is the only caller, and it doesn't need the generality of the function. We already know there is no iommu_group, so it is simply two function calls. Moving it here allows the following patches to split the logic in these functions. Reviewed-by: Kevin Tian Reviewed-by: Lu Baolu Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/3-v3-328044aa278c+45e49-iommu_probe_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 50 ++++++++----------------------------------- 1 file changed, 9 insertions(+), 41 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 2f16f988ab363..bd56cf02bc998 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -127,7 +127,6 @@ static int iommu_setup_default_domain(struct iommu_group *group, int target_type); static int iommu_create_device_direct_mappings(struct iommu_domain *domain, struct device *dev); -static struct iommu_group *iommu_group_get_for_dev(struct device *dev); static ssize_t iommu_group_store_type(struct iommu_group *group, const char *buf, size_t count); @@ -379,12 +378,18 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list if (ops->is_attach_deferred) dev->iommu->attach_deferred = ops->is_attach_deferred(dev); - group = iommu_group_get_for_dev(dev); + group = ops->device_group(dev); + if (WARN_ON_ONCE(group == NULL)) + group = ERR_PTR(-EINVAL); if (IS_ERR(group)) { ret = PTR_ERR(group); goto out_release; } + ret = iommu_group_add_device(group, dev); + if (ret) + goto err_put_group; + mutex_lock(&group->mutex); if (group_list && !group->default_domain && list_empty(&group->entry)) list_add_tail(&group->entry, group_list); @@ -396,6 +401,8 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list return 0; +err_put_group: + iommu_group_put(group); out_release: if (ops->release_device) ops->release_device(dev); @@ -1670,45 +1677,6 @@ iommu_group_alloc_default_domain(struct iommu_group *group, int req_type) return dom; } -/** - * iommu_group_get_for_dev - Find or create the IOMMU group for a device - * @dev: target device - * - * This function is intended to be called by IOMMU drivers and extended to - * support common, bus-defined algorithms when determining or creating the - * IOMMU group for a device. On success, the caller will hold a reference - * to the returned IOMMU group, which will already include the provided - * device. The reference should be released with iommu_group_put(). - */ -static struct iommu_group *iommu_group_get_for_dev(struct device *dev) -{ - const struct iommu_ops *ops = dev_iommu_ops(dev); - struct iommu_group *group; - int ret; - - group = iommu_group_get(dev); - if (group) - return group; - - group = ops->device_group(dev); - if (WARN_ON_ONCE(group == NULL)) - return ERR_PTR(-EINVAL); - - if (IS_ERR(group)) - return group; - - ret = iommu_group_add_device(group, dev); - if (ret) - goto out_put_group; - - return group; - -out_put_group: - iommu_group_put(group); - - return ERR_PTR(ret); -} - struct iommu_domain *iommu_group_default_domain(struct iommu_group *group) { return group->default_domain; -- GitLab From df15d76dcacac2126a4d20ba06c9d7e4b18bad8e Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 5 Jun 2023 21:59:42 -0300 Subject: [PATCH 0187/3445] iommu: Simplify the __iommu_group_remove_device() flow Instead of returning the struct group_device and then later freeing it, do the entire free under the group->mutex and defer only putting the iommu_group. It is safe to remove the sysfs_links and free memory while holding that mutex. Move the sanity assert of the group status into __iommu_group_free_device(). The next patch will improve upon this and consolidate the group put and the mutex into __iommu_group_remove_device(). __iommu_group_free_device() is close to being the paired undo of iommu_group_add_device(), following patches will improve on that. Reviewed-by: Kevin Tian Reviewed-by: Lu Baolu Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/4-v3-328044aa278c+45e49-iommu_probe_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 83 ++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 44 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index bd56cf02bc998..6cf4da060e94a 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -470,32 +470,8 @@ err_out: } -/* - * Remove a device from a group's device list and return the group device - * if successful. - */ -static struct group_device * -__iommu_group_remove_device(struct iommu_group *group, struct device *dev) -{ - struct group_device *device; - - lockdep_assert_held(&group->mutex); - for_each_group_device(group, device) { - if (device->dev == dev) { - list_del(&device->list); - return device; - } - } - - return NULL; -} - -/* - * Release a device from its group and decrements the iommu group reference - * count. - */ -static void __iommu_group_release_device(struct iommu_group *group, - struct group_device *grp_dev) +static void __iommu_group_free_device(struct iommu_group *group, + struct group_device *grp_dev) { struct device *dev = grp_dev->dev; @@ -504,16 +480,45 @@ static void __iommu_group_release_device(struct iommu_group *group, trace_remove_device_from_group(group->id, dev); + /* + * If the group has become empty then ownership must have been + * released, and the current domain must be set back to NULL or + * the default domain. + */ + if (list_empty(&group->devices)) + WARN_ON(group->owner_cnt || + group->domain != group->default_domain); + kfree(grp_dev->name); kfree(grp_dev); dev->iommu_group = NULL; - iommu_group_put(group); } -static void iommu_release_device(struct device *dev) +/* + * Remove the iommu_group from the struct device. The attached group must be put + * by the caller after releaseing the group->mutex. + */ +static void __iommu_group_remove_device(struct device *dev) { struct iommu_group *group = dev->iommu_group; struct group_device *device; + + lockdep_assert_held(&group->mutex); + for_each_group_device(group, device) { + if (device->dev != dev) + continue; + + list_del(&device->list); + __iommu_group_free_device(group, device); + /* Caller must put iommu_group */ + return; + } + WARN(true, "Corrupted iommu_group device_list"); +} + +static void iommu_release_device(struct device *dev) +{ + struct iommu_group *group = dev->iommu_group; const struct iommu_ops *ops; if (!dev->iommu || !group) @@ -522,16 +527,7 @@ static void iommu_release_device(struct device *dev) iommu_device_unlink(dev->iommu->iommu_dev, dev); mutex_lock(&group->mutex); - device = __iommu_group_remove_device(group, dev); - - /* - * If the group has become empty then ownership must have been released, - * and the current domain must be set back to NULL or the default - * domain. - */ - if (list_empty(&group->devices)) - WARN_ON(group->owner_cnt || - group->domain != group->default_domain); + __iommu_group_remove_device(dev); /* * release_device() must stop using any attached domain on the device. @@ -547,8 +543,8 @@ static void iommu_release_device(struct device *dev) ops->release_device(dev); mutex_unlock(&group->mutex); - if (device) - __iommu_group_release_device(group, device); + /* Pairs with the get in iommu_group_add_device() */ + iommu_group_put(group); module_put(ops->owner); dev_iommu_free(dev); @@ -1107,7 +1103,6 @@ EXPORT_SYMBOL_GPL(iommu_group_add_device); void iommu_group_remove_device(struct device *dev) { struct iommu_group *group = dev->iommu_group; - struct group_device *device; if (!group) return; @@ -1115,11 +1110,11 @@ void iommu_group_remove_device(struct device *dev) dev_info(dev, "Removing from iommu group %d\n", group->id); mutex_lock(&group->mutex); - device = __iommu_group_remove_device(group, dev); + __iommu_group_remove_device(dev); mutex_unlock(&group->mutex); - if (device) - __iommu_group_release_device(group, device); + /* Pairs with the get in iommu_group_add_device() */ + iommu_group_put(group); } EXPORT_SYMBOL_GPL(iommu_group_remove_device); -- GitLab From aa0958570f24f562422afa41fefd1b3a1fe0f6d0 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 5 Jun 2023 21:59:43 -0300 Subject: [PATCH 0188/3445] iommu: Add iommu_init/deinit_device() paired functions Move the driver init and destruction code into two logically paired functions. There is a subtle ordering dependency in how the group's domains are freed, the current code does the kobject_put() on the group which will hopefully trigger the free of the domains before the module_put() that protects the domain->ops. Reorganize this to be explicit and documented. The domains are cleaned up by iommu_deinit_device() if it is the last device to be deinit'd from the group. This must be done in a specific order - after ops->release_device() and before the module_put(). Make it very clear and obvious by putting the order directly in one function. Leave WARN_ON's in case the refcounting gets messed up somehow. This also moves the module_put() and dev_iommu_free() under the group->mutex to keep the code simple. Building paired functions like this helps ensure that error cleanup flows in __iommu_probe_device() are correct because they share the same code that handles the normal flow. These details become relavent as following patches add more error unwind into __iommu_probe_device(), and ultimately a following series adds fine-grained locking to __iommu_probe_device(). Reviewed-by: Kevin Tian Reviewed-by: Lu Baolu Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/5-v3-328044aa278c+45e49-iommu_probe_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 191 +++++++++++++++++++++++++----------------- 1 file changed, 112 insertions(+), 79 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 6cf4da060e94a..f052f52958fdc 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -332,10 +332,99 @@ static u32 dev_iommu_get_max_pasids(struct device *dev) return min_t(u32, max_pasids, dev->iommu->iommu_dev->max_pasids); } +/* + * Init the dev->iommu and dev->iommu_group in the struct device and get the + * driver probed + */ +static int iommu_init_device(struct device *dev, const struct iommu_ops *ops) +{ + struct iommu_device *iommu_dev; + struct iommu_group *group; + int ret; + + if (!dev_iommu_get(dev)) + return -ENOMEM; + + if (!try_module_get(ops->owner)) { + ret = -EINVAL; + goto err_free; + } + + iommu_dev = ops->probe_device(dev); + if (IS_ERR(iommu_dev)) { + ret = PTR_ERR(iommu_dev); + goto err_module_put; + } + + group = ops->device_group(dev); + if (WARN_ON_ONCE(group == NULL)) + group = ERR_PTR(-EINVAL); + if (IS_ERR(group)) { + ret = PTR_ERR(group); + goto err_release; + } + dev->iommu_group = group; + + dev->iommu->iommu_dev = iommu_dev; + dev->iommu->max_pasids = dev_iommu_get_max_pasids(dev); + if (ops->is_attach_deferred) + dev->iommu->attach_deferred = ops->is_attach_deferred(dev); + return 0; + +err_release: + if (ops->release_device) + ops->release_device(dev); +err_module_put: + module_put(ops->owner); +err_free: + dev_iommu_free(dev); + return ret; +} + +static void iommu_deinit_device(struct device *dev) +{ + struct iommu_group *group = dev->iommu_group; + const struct iommu_ops *ops = dev_iommu_ops(dev); + + lockdep_assert_held(&group->mutex); + + /* + * release_device() must stop using any attached domain on the device. + * If there are still other devices in the group they are not effected + * by this callback. + * + * The IOMMU driver must set the device to either an identity or + * blocking translation and stop using any domain pointer, as it is + * going to be freed. + */ + if (ops->release_device) + ops->release_device(dev); + + /* + * If this is the last driver to use the group then we must free the + * domains before we do the module_put(). + */ + if (list_empty(&group->devices)) { + if (group->default_domain) { + iommu_domain_free(group->default_domain); + group->default_domain = NULL; + } + if (group->blocking_domain) { + iommu_domain_free(group->blocking_domain); + group->blocking_domain = NULL; + } + group->domain = NULL; + } + + /* Caller must put iommu_group */ + dev->iommu_group = NULL; + module_put(ops->owner); + dev_iommu_free(dev); +} + static int __iommu_probe_device(struct device *dev, struct list_head *group_list) { const struct iommu_ops *ops = dev->bus->iommu_ops; - struct iommu_device *iommu_dev; struct iommu_group *group; static DEFINE_MUTEX(iommu_probe_device_lock); int ret; @@ -357,62 +446,30 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list goto out_unlock; } - if (!dev_iommu_get(dev)) { - ret = -ENOMEM; + ret = iommu_init_device(dev, ops); + if (ret) goto out_unlock; - } - - if (!try_module_get(ops->owner)) { - ret = -EINVAL; - goto err_free; - } - - iommu_dev = ops->probe_device(dev); - if (IS_ERR(iommu_dev)) { - ret = PTR_ERR(iommu_dev); - goto out_module_put; - } - - dev->iommu->iommu_dev = iommu_dev; - dev->iommu->max_pasids = dev_iommu_get_max_pasids(dev); - if (ops->is_attach_deferred) - dev->iommu->attach_deferred = ops->is_attach_deferred(dev); - - group = ops->device_group(dev); - if (WARN_ON_ONCE(group == NULL)) - group = ERR_PTR(-EINVAL); - if (IS_ERR(group)) { - ret = PTR_ERR(group); - goto out_release; - } + group = dev->iommu_group; ret = iommu_group_add_device(group, dev); + mutex_lock(&group->mutex); if (ret) goto err_put_group; - mutex_lock(&group->mutex); if (group_list && !group->default_domain && list_empty(&group->entry)) list_add_tail(&group->entry, group_list); mutex_unlock(&group->mutex); iommu_group_put(group); mutex_unlock(&iommu_probe_device_lock); - iommu_device_link(iommu_dev, dev); + iommu_device_link(dev->iommu->iommu_dev, dev); return 0; err_put_group: + iommu_deinit_device(dev); + mutex_unlock(&group->mutex); iommu_group_put(group); -out_release: - if (ops->release_device) - ops->release_device(dev); - -out_module_put: - module_put(ops->owner); - -err_free: - dev_iommu_free(dev); - out_unlock: mutex_unlock(&iommu_probe_device_lock); @@ -491,63 +548,45 @@ static void __iommu_group_free_device(struct iommu_group *group, kfree(grp_dev->name); kfree(grp_dev); - dev->iommu_group = NULL; } -/* - * Remove the iommu_group from the struct device. The attached group must be put - * by the caller after releaseing the group->mutex. - */ +/* Remove the iommu_group from the struct device. */ static void __iommu_group_remove_device(struct device *dev) { struct iommu_group *group = dev->iommu_group; struct group_device *device; - lockdep_assert_held(&group->mutex); + mutex_lock(&group->mutex); for_each_group_device(group, device) { if (device->dev != dev) continue; list_del(&device->list); __iommu_group_free_device(group, device); - /* Caller must put iommu_group */ - return; + if (dev->iommu && dev->iommu->iommu_dev) + iommu_deinit_device(dev); + else + dev->iommu_group = NULL; + goto out; } WARN(true, "Corrupted iommu_group device_list"); +out: + mutex_unlock(&group->mutex); + + /* Pairs with the get in iommu_group_add_device() */ + iommu_group_put(group); } static void iommu_release_device(struct device *dev) { struct iommu_group *group = dev->iommu_group; - const struct iommu_ops *ops; if (!dev->iommu || !group) return; iommu_device_unlink(dev->iommu->iommu_dev, dev); - mutex_lock(&group->mutex); __iommu_group_remove_device(dev); - - /* - * release_device() must stop using any attached domain on the device. - * If there are still other devices in the group they are not effected - * by this callback. - * - * The IOMMU driver must set the device to either an identity or - * blocking translation and stop using any domain pointer, as it is - * going to be freed. - */ - ops = dev_iommu_ops(dev); - if (ops->release_device) - ops->release_device(dev); - mutex_unlock(&group->mutex); - - /* Pairs with the get in iommu_group_add_device() */ - iommu_group_put(group); - - module_put(ops->owner); - dev_iommu_free(dev); } static int __init iommu_set_def_domain_type(char *str) @@ -808,10 +847,9 @@ static void iommu_group_release(struct kobject *kobj) ida_free(&iommu_group_ida, group->id); - if (group->default_domain) - iommu_domain_free(group->default_domain); - if (group->blocking_domain) - iommu_domain_free(group->blocking_domain); + /* Domains are free'd by iommu_deinit_device() */ + WARN_ON(group->default_domain); + WARN_ON(group->blocking_domain); kfree(group->name); kfree(group); @@ -1109,12 +1147,7 @@ void iommu_group_remove_device(struct device *dev) dev_info(dev, "Removing from iommu group %d\n", group->id); - mutex_lock(&group->mutex); __iommu_group_remove_device(dev); - mutex_unlock(&group->mutex); - - /* Pairs with the get in iommu_group_add_device() */ - iommu_group_put(group); } EXPORT_SYMBOL_GPL(iommu_group_remove_device); -- GitLab From 14891af3799e8cd24dee14f78c31fa663cfb5ba9 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 5 Jun 2023 21:59:44 -0300 Subject: [PATCH 0189/3445] iommu: Move the iommu driver sysfs setup into iommu_init/deinit_device() It makes logical sense that once the driver is attached to the device the sysfs links appear, even if we haven't fully created the group_device or attached the device to a domain. Fix the missing error handling on sysfs creation since iommu_init_device() can trivially handle this. Reviewed-by: Kevin Tian Reviewed-by: Lu Baolu Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/6-v3-328044aa278c+45e49-iommu_probe_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu-sysfs.c | 6 ------ drivers/iommu/iommu.c | 13 +++++++++---- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/iommu/iommu-sysfs.c b/drivers/iommu/iommu-sysfs.c index 99869217fbec7..c8aba0e2a30d7 100644 --- a/drivers/iommu/iommu-sysfs.c +++ b/drivers/iommu/iommu-sysfs.c @@ -107,9 +107,6 @@ int iommu_device_link(struct iommu_device *iommu, struct device *link) { int ret; - if (!iommu || IS_ERR(iommu)) - return -ENODEV; - ret = sysfs_add_link_to_group(&iommu->dev->kobj, "devices", &link->kobj, dev_name(link)); if (ret) @@ -126,9 +123,6 @@ EXPORT_SYMBOL_GPL(iommu_device_link); void iommu_device_unlink(struct iommu_device *iommu, struct device *link) { - if (!iommu || IS_ERR(iommu)) - return; - sysfs_remove_link(&link->kobj, "iommu"); sysfs_remove_link_from_group(&iommu->dev->kobj, "devices", dev_name(link)); } diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index f052f52958fdc..4688f61b7a4f2 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -356,12 +356,16 @@ static int iommu_init_device(struct device *dev, const struct iommu_ops *ops) goto err_module_put; } + ret = iommu_device_link(iommu_dev, dev); + if (ret) + goto err_release; + group = ops->device_group(dev); if (WARN_ON_ONCE(group == NULL)) group = ERR_PTR(-EINVAL); if (IS_ERR(group)) { ret = PTR_ERR(group); - goto err_release; + goto err_unlink; } dev->iommu_group = group; @@ -371,6 +375,8 @@ static int iommu_init_device(struct device *dev, const struct iommu_ops *ops) dev->iommu->attach_deferred = ops->is_attach_deferred(dev); return 0; +err_unlink: + iommu_device_unlink(iommu_dev, dev); err_release: if (ops->release_device) ops->release_device(dev); @@ -388,6 +394,8 @@ static void iommu_deinit_device(struct device *dev) lockdep_assert_held(&group->mutex); + iommu_device_unlink(dev->iommu->iommu_dev, dev); + /* * release_device() must stop using any attached domain on the device. * If there are still other devices in the group they are not effected @@ -462,7 +470,6 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list iommu_group_put(group); mutex_unlock(&iommu_probe_device_lock); - iommu_device_link(dev->iommu->iommu_dev, dev); return 0; @@ -584,8 +591,6 @@ static void iommu_release_device(struct device *dev) if (!dev->iommu || !group) return; - iommu_device_unlink(dev->iommu->iommu_dev, dev); - __iommu_group_remove_device(dev); } -- GitLab From 9a108996b5b39c8b7b4911bd4fe7f9ad87bc0f72 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 5 Jun 2023 21:59:45 -0300 Subject: [PATCH 0190/3445] iommu: Do not export iommu_device_link/unlink() These are not used outside iommu.c, they should not be available to modular code. Reviewed-by: Kevin Tian Reviewed-by: Lu Baolu Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/7-v3-328044aa278c+45e49-iommu_probe_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu-sysfs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/iommu/iommu-sysfs.c b/drivers/iommu/iommu-sysfs.c index c8aba0e2a30d7..cbe378c34ba3e 100644 --- a/drivers/iommu/iommu-sysfs.c +++ b/drivers/iommu/iommu-sysfs.c @@ -119,11 +119,9 @@ int iommu_device_link(struct iommu_device *iommu, struct device *link) return ret; } -EXPORT_SYMBOL_GPL(iommu_device_link); void iommu_device_unlink(struct iommu_device *iommu, struct device *link) { sysfs_remove_link(&link->kobj, "iommu"); sysfs_remove_link_from_group(&iommu->dev->kobj, "devices", dev_name(link)); } -EXPORT_SYMBOL_GPL(iommu_device_unlink); -- GitLab From cfb6ee65f7603a0605fa8f5fe5b0782f0731c81c Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 5 Jun 2023 21:59:46 -0300 Subject: [PATCH 0191/3445] iommu: Always destroy the iommu_group during iommu_release_device() Have release fully clean up the iommu related parts of the struct device, no matter what state they are in. Split the logic so that the three things owned by the iommu core are always cleaned up: - Any attached iommu_group - Any allocated dev->iommu and its contents including a fwsepc - Any attached driver via a struct group_device This fixes a minor bug where a fwspec created without an iommu_group being probed would not be freed. Reviewed-by: Kevin Tian Reviewed-by: Lu Baolu Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/8-v3-328044aa278c+45e49-iommu_probe_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 4688f61b7a4f2..55b916e8da3bb 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -574,10 +574,8 @@ static void __iommu_group_remove_device(struct device *dev) iommu_deinit_device(dev); else dev->iommu_group = NULL; - goto out; + break; } - WARN(true, "Corrupted iommu_group device_list"); -out: mutex_unlock(&group->mutex); /* Pairs with the get in iommu_group_add_device() */ @@ -588,10 +586,12 @@ static void iommu_release_device(struct device *dev) { struct iommu_group *group = dev->iommu_group; - if (!dev->iommu || !group) - return; + if (group) + __iommu_group_remove_device(dev); - __iommu_group_remove_device(dev); + /* Free any fwspec if no iommu_driver was ever attached */ + if (dev->iommu) + dev_iommu_free(dev); } static int __init iommu_set_def_domain_type(char *str) -- GitLab From fa08280364882c42993dc5d8394c467d76803fdb Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 5 Jun 2023 21:59:47 -0300 Subject: [PATCH 0192/3445] iommu: Split iommu_group_add_device() Move the list_add_tail() for the group_device into the critical region that immediately follows in __iommu_probe_device(). This avoids one case of unlocking and immediately re-locking the group->mutex. Consistently make the caller responsible for setting dev->iommu_group, prior patches moved this into iommu_init_device(), make the no-driver path do this in iommu_group_add_device(). This completes making __iommu_group_free_device() and iommu_group_alloc_device() into pair'd functions. Reviewed-by: Lu Baolu Reviewed-by: Kevin Tian Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/9-v3-328044aa278c+45e49-iommu_probe_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 66 ++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 55b916e8da3bb..3129e5c50c875 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -129,6 +129,8 @@ static int iommu_create_device_direct_mappings(struct iommu_domain *domain, struct device *dev); static ssize_t iommu_group_store_type(struct iommu_group *group, const char *buf, size_t count); +static struct group_device *iommu_group_alloc_device(struct iommu_group *group, + struct device *dev); #define IOMMU_GROUP_ATTR(_name, _mode, _show, _store) \ struct iommu_group_attribute iommu_group_attr_##_name = \ @@ -435,6 +437,7 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list const struct iommu_ops *ops = dev->bus->iommu_ops; struct iommu_group *group; static DEFINE_MUTEX(iommu_probe_device_lock); + struct group_device *gdev; int ret; if (!ops) @@ -459,16 +462,17 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list goto out_unlock; group = dev->iommu_group; - ret = iommu_group_add_device(group, dev); + gdev = iommu_group_alloc_device(group, dev); mutex_lock(&group->mutex); - if (ret) + if (IS_ERR(gdev)) { + ret = PTR_ERR(gdev); goto err_put_group; + } + list_add_tail(&gdev->list, &group->devices); if (group_list && !group->default_domain && list_empty(&group->entry)) list_add_tail(&group->entry, group_list); mutex_unlock(&group->mutex); - iommu_group_put(group); - mutex_unlock(&iommu_probe_device_lock); return 0; @@ -578,7 +582,10 @@ static void __iommu_group_remove_device(struct device *dev) } mutex_unlock(&group->mutex); - /* Pairs with the get in iommu_group_add_device() */ + /* + * Pairs with the get in iommu_init_device() or + * iommu_group_add_device() + */ iommu_group_put(group); } @@ -1067,22 +1074,16 @@ out: return ret; } -/** - * iommu_group_add_device - add a device to an iommu group - * @group: the group into which to add the device (reference should be held) - * @dev: the device - * - * This function is called by an iommu driver to add a device into a - * group. Adding a device increments the group reference count. - */ -int iommu_group_add_device(struct iommu_group *group, struct device *dev) +/* This is undone by __iommu_group_free_device() */ +static struct group_device *iommu_group_alloc_device(struct iommu_group *group, + struct device *dev) { int ret, i = 0; struct group_device *device; device = kzalloc(sizeof(*device), GFP_KERNEL); if (!device) - return -ENOMEM; + return ERR_PTR(-ENOMEM); device->dev = dev; @@ -1113,17 +1114,11 @@ rename: goto err_free_name; } - iommu_group_ref_get(group); - dev->iommu_group = group; - - mutex_lock(&group->mutex); - list_add_tail(&device->list, &group->devices); - mutex_unlock(&group->mutex); trace_add_device_to_group(group->id, dev); dev_info(dev, "Adding to iommu group %d\n", group->id); - return 0; + return device; err_free_name: kfree(device->name); @@ -1132,7 +1127,32 @@ err_remove_link: err_free_device: kfree(device); dev_err(dev, "Failed to add to iommu group %d: %d\n", group->id, ret); - return ret; + return ERR_PTR(ret); +} + +/** + * iommu_group_add_device - add a device to an iommu group + * @group: the group into which to add the device (reference should be held) + * @dev: the device + * + * This function is called by an iommu driver to add a device into a + * group. Adding a device increments the group reference count. + */ +int iommu_group_add_device(struct iommu_group *group, struct device *dev) +{ + struct group_device *gdev; + + gdev = iommu_group_alloc_device(group, dev); + if (IS_ERR(gdev)) + return PTR_ERR(gdev); + + iommu_group_ref_get(group); + dev->iommu_group = group; + + mutex_lock(&group->mutex); + list_add_tail(&gdev->list, &group->devices); + mutex_unlock(&group->mutex); + return 0; } EXPORT_SYMBOL_GPL(iommu_group_add_device); -- GitLab From f188056352bcdcd4bec31c22baa00ba6568f1416 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 5 Jun 2023 21:59:48 -0300 Subject: [PATCH 0193/3445] iommu: Avoid locking/unlocking for iommu_probe_device() Remove the race where a hotplug of a device into an existing group will have the device installed in the group->devices, but not yet attached to the group's current domain. Move the group attachment logic from iommu_probe_device() and put it under the same mutex that updates the group->devices list so everything is atomic under the lock. We retain the two step setup of the default domain for the bus_iommu_probe() case solely so that we have a more complete view of the group when creating the default domain for boot time devices. This is not generally necessary with the current code structure but seems to be supporting some odd corner cases like alias RID's and IOMMU_RESV_DIRECT or driver bugs returning different default_domain types for the same group. During bus_iommu_probe() the group will have a device list but both group->default_domain and group->domain will be NULL. Reviewed-by: Lu Baolu Reviewed-by: Kevin Tian Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/r/10-v3-328044aa278c+45e49-iommu_probe_jgg@nvidia.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 78 +++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 43 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 3129e5c50c875..42377f49ab871 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -131,6 +131,8 @@ static ssize_t iommu_group_store_type(struct iommu_group *group, const char *buf, size_t count); static struct group_device *iommu_group_alloc_device(struct iommu_group *group, struct device *dev); +static void __iommu_group_free_device(struct iommu_group *group, + struct group_device *grp_dev); #define IOMMU_GROUP_ATTR(_name, _mode, _show, _store) \ struct iommu_group_attribute iommu_group_attr_##_name = \ @@ -469,14 +471,39 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list goto err_put_group; } + /* + * The gdev must be in the list before calling + * iommu_setup_default_domain() + */ list_add_tail(&gdev->list, &group->devices); - if (group_list && !group->default_domain && list_empty(&group->entry)) - list_add_tail(&group->entry, group_list); + WARN_ON(group->default_domain && !group->domain); + if (group->default_domain) + iommu_create_device_direct_mappings(group->default_domain, dev); + if (group->domain) { + ret = __iommu_device_set_domain(group, dev, group->domain, 0); + if (ret) + goto err_remove_gdev; + } else if (!group->default_domain && !group_list) { + ret = iommu_setup_default_domain(group, 0); + if (ret) + goto err_remove_gdev; + } else if (!group->default_domain) { + /* + * With a group_list argument we defer the default_domain setup + * to the caller by providing a de-duplicated list of groups + * that need further setup. + */ + if (list_empty(&group->entry)) + list_add_tail(&group->entry, group_list); + } mutex_unlock(&group->mutex); mutex_unlock(&iommu_probe_device_lock); return 0; +err_remove_gdev: + list_del(&gdev->list); + __iommu_group_free_device(group, gdev); err_put_group: iommu_deinit_device(dev); mutex_unlock(&group->mutex); @@ -490,52 +517,17 @@ out_unlock: int iommu_probe_device(struct device *dev) { const struct iommu_ops *ops; - struct iommu_group *group; int ret; ret = __iommu_probe_device(dev, NULL); if (ret) - goto err_out; - - group = iommu_group_get(dev); - if (!group) { - ret = -ENODEV; - goto err_release; - } - - mutex_lock(&group->mutex); - - if (group->default_domain) - iommu_create_device_direct_mappings(group->default_domain, dev); - - if (group->domain) { - ret = __iommu_device_set_domain(group, dev, group->domain, 0); - if (ret) - goto err_unlock; - } else if (!group->default_domain) { - ret = iommu_setup_default_domain(group, 0); - if (ret) - goto err_unlock; - } - - mutex_unlock(&group->mutex); - iommu_group_put(group); + return ret; ops = dev_iommu_ops(dev); if (ops->probe_finalize) ops->probe_finalize(dev); return 0; - -err_unlock: - mutex_unlock(&group->mutex); - iommu_group_put(group); -err_release: - iommu_release_device(dev); - -err_out: - return ret; - } static void __iommu_group_free_device(struct iommu_group *group, @@ -1815,11 +1807,6 @@ int bus_iommu_probe(const struct bus_type *bus) LIST_HEAD(group_list); int ret; - /* - * This code-path does not allocate the default domain when - * creating the iommu group, so do it after the groups are - * created. - */ ret = bus_for_each_dev(bus, NULL, &group_list, probe_iommu_group); if (ret) return ret; @@ -1832,6 +1819,11 @@ int bus_iommu_probe(const struct bus_type *bus) /* Remove item from the list */ list_del_init(&group->entry); + /* + * We go to the trouble of deferred default domain creation so + * that the cross-group default domain type and the setup of the + * IOMMU_RESV_DIRECT will work correctly in non-hotpug scenarios. + */ ret = iommu_setup_default_domain(group, 0); if (ret) { mutex_unlock(&group->mutex); -- GitLab From 791c2b17fb4023f21c3cbf5f268af01d9b8cb7cc Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Thu, 13 Apr 2023 14:40:25 +0100 Subject: [PATCH 0194/3445] iommu: Optimise PCI SAC address trick Per the reasoning in commit 4bf7fda4dce2 ("iommu/dma: Add config for PCI SAC address trick") and its subsequent revert, this mechanism no longer serves its original purpose, but now only works around broken hardware/drivers in a way that is unfortunately too impactful to remove. This does not, however, prevent us from solving the performance impact which that workaround has on large-scale systems that don't need it. Once the 32-bit IOVA space fills up and a workload starts allocating and freeing on both sides of the boundary, the opportunistic SAC allocation can then end up spending significant time hunting down scattered fragments of free 32-bit space, or just reestablishing max32_alloc_size. This can easily be exacerbated by a change in allocation pattern, such as by changing the network MTU, which can increase pressure on the 32-bit space by leaving a large quantity of cached IOVAs which are now the wrong size to be recycled, but also won't be freed since the non-opportunistic allocations can still be satisfied from the whole 64-bit space without triggering the reclaim path. However, in the context of a workaround where smaller DMA addresses aren't simply a preference but a necessity, if we get to that point at all then in fact it's already the endgame. The nature of the allocator is currently such that the first IOVA we give to a device after the 32-bit space runs out will be the highest possible address for that device, ever. If that works, then great, we know we can optimise for speed by always allocating from the full range. And if it doesn't, then the worst has already happened and any brokenness is now showing, so there's little point in continuing to try to hide it. To that end, implement a flag to refine the SAC business into a per-device policy that can automatically get itself out of the way if and when it stops being useful. CC: Linus Torvalds CC: Jakub Kicinski Reviewed-by: John Garry Signed-off-by: Robin Murphy Tested-by: Vasant Hegde Tested-by: Jakub Kicinski Link: https://lore.kernel.org/r/b8502b115b915d2a3fabde367e099e39106686c8.1681392791.git.robin.murphy@arm.com Signed-off-by: Joerg Roedel --- drivers/iommu/dma-iommu.c | 26 ++++++++++++++++++++------ drivers/iommu/dma-iommu.h | 8 ++++++++ drivers/iommu/iommu.c | 3 +++ include/linux/iommu.h | 2 ++ 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index e577241638350..4b1a88f514c9c 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -660,7 +660,7 @@ static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain *domain, { struct iommu_dma_cookie *cookie = domain->iova_cookie; struct iova_domain *iovad = &cookie->iovad; - unsigned long shift, iova_len, iova = 0; + unsigned long shift, iova_len, iova; if (cookie->type == IOMMU_DMA_MSI_COOKIE) { cookie->msi_iova += size; @@ -675,15 +675,29 @@ static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain *domain, if (domain->geometry.force_aperture) dma_limit = min(dma_limit, (u64)domain->geometry.aperture_end); - /* Try to get PCI devices a SAC address */ - if (dma_limit > DMA_BIT_MASK(32) && !iommu_dma_forcedac && dev_is_pci(dev)) + /* + * Try to use all the 32-bit PCI addresses first. The original SAC vs. + * DAC reasoning loses relevance with PCIe, but enough hardware and + * firmware bugs are still lurking out there that it's safest not to + * venture into the 64-bit space until necessary. + * + * If your device goes wrong after seeing the notice then likely either + * its driver is not setting DMA masks accurately, the hardware has + * some inherent bug in handling >32-bit addresses, or not all the + * expected address bits are wired up between the device and the IOMMU. + */ + if (dma_limit > DMA_BIT_MASK(32) && dev->iommu->pci_32bit_workaround) { iova = alloc_iova_fast(iovad, iova_len, DMA_BIT_MASK(32) >> shift, false); + if (iova) + goto done; - if (!iova) - iova = alloc_iova_fast(iovad, iova_len, dma_limit >> shift, - true); + dev->iommu->pci_32bit_workaround = false; + dev_notice(dev, "Using %d-bit DMA addresses\n", bits_per(dma_limit)); + } + iova = alloc_iova_fast(iovad, iova_len, dma_limit >> shift, true); +done: return (dma_addr_t)iova << shift; } diff --git a/drivers/iommu/dma-iommu.h b/drivers/iommu/dma-iommu.h index 9427900092922..c829f1f82a991 100644 --- a/drivers/iommu/dma-iommu.h +++ b/drivers/iommu/dma-iommu.h @@ -17,6 +17,10 @@ int iommu_dma_init_fq(struct iommu_domain *domain); void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list); extern bool iommu_dma_forcedac; +static inline void iommu_dma_set_pci_32bit_workaround(struct device *dev) +{ + dev->iommu->pci_32bit_workaround = !iommu_dma_forcedac; +} #else /* CONFIG_IOMMU_DMA */ @@ -38,5 +42,9 @@ static inline void iommu_dma_get_resv_regions(struct device *dev, struct list_he { } +static inline void iommu_dma_set_pci_32bit_workaround(struct device *dev) +{ +} + #endif /* CONFIG_IOMMU_DMA */ #endif /* __DMA_IOMMU_H */ diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 42377f49ab871..e67f6562da73b 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -499,6 +499,9 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list mutex_unlock(&group->mutex); mutex_unlock(&iommu_probe_device_lock); + if (dev_is_pci(dev)) + iommu_dma_set_pci_32bit_workaround(dev); + return 0; err_remove_gdev: diff --git a/include/linux/iommu.h b/include/linux/iommu.h index d316425966759..b1dcb1b9b1704 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -409,6 +409,7 @@ struct iommu_fault_param { * @priv: IOMMU Driver private data * @max_pasids: number of PASIDs this device can consume * @attach_deferred: the dma domain attachment is deferred + * @pci_32bit_workaround: Limit DMA allocations to 32-bit IOVAs * * TODO: migrate other per device data pointers under iommu_dev_data, e.g. * struct iommu_group *iommu_group; @@ -422,6 +423,7 @@ struct dev_iommu { void *priv; u32 max_pasids; u32 attach_deferred:1; + u32 pci_32bit_workaround:1; }; int iommu_device_register(struct iommu_device *iommu, -- GitLab From 534103bcd52ca9c1fecbc70e717b4a538dc4ded8 Mon Sep 17 00:00:00 2001 From: Daniel Marcovitch Date: Fri, 9 Jun 2023 10:51:45 +0000 Subject: [PATCH 0195/3445] iommu/amd/iommu_v2: Fix pasid_state refcount dec hit 0 warning on pasid unbind When unbinding pasid - a race condition exists vs outstanding page faults. To prevent this, the pasid_state object contains a refcount. * set to 1 on pasid bind * incremented on each ppr notification start * decremented on each ppr notification done * decremented on pasid unbind Since refcount_dec assumes that refcount will never reach 0: the current implementation causes the following to be invoked on pasid unbind: REFCOUNT_WARN("decrement hit 0; leaking memory") Fix this issue by changing refcount_dec to refcount_dec_and_test to explicitly handle refcount=1. Fixes: 8bc54824da4e ("iommu/amd: Convert from atomic_t to refcount_t on pasid_state->count") Signed-off-by: Daniel Marcovitch Signed-off-by: Vasant Hegde Link: https://lore.kernel.org/r/20230609105146.7773-2-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/iommu_v2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/amd/iommu_v2.c b/drivers/iommu/amd/iommu_v2.c index 261352a232716..65d78d7e04408 100644 --- a/drivers/iommu/amd/iommu_v2.c +++ b/drivers/iommu/amd/iommu_v2.c @@ -262,8 +262,8 @@ static void put_pasid_state(struct pasid_state *pasid_state) static void put_pasid_state_wait(struct pasid_state *pasid_state) { - refcount_dec(&pasid_state->count); - wait_event(pasid_state->wq, !refcount_read(&pasid_state->count)); + if (!refcount_dec_and_test(&pasid_state->count)) + wait_event(pasid_state->wq, !refcount_read(&pasid_state->count)); free_pasid_state(pasid_state); } -- GitLab From d269ab61f4f8c56999fd26ade86def26db1fed09 Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Fri, 9 Jun 2023 10:51:46 +0000 Subject: [PATCH 0196/3445] iommu/amd/iommu_v2: Clear pasid state in free path Clear pasid state in device amd_iommu_free_device() path. It will make sure no new ppr notifier is registered in free path. Suggested-by: Jason Gunthorpe Signed-off-by: Vasant Hegde Link: https://lore.kernel.org/r/20230609105146.7773-3-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/iommu_v2.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/iommu/amd/iommu_v2.c b/drivers/iommu/amd/iommu_v2.c index 65d78d7e04408..c5825e0a6770f 100644 --- a/drivers/iommu/amd/iommu_v2.c +++ b/drivers/iommu/amd/iommu_v2.c @@ -327,6 +327,9 @@ static void free_pasid_states(struct device_state *dev_state) put_pasid_state(pasid_state); + /* Clear the pasid state so that the pasid can be re-used */ + clear_pasid_state(dev_state, pasid_state->pasid); + /* * This will call the mn_release function and * unbind the PASID -- GitLab From 6df63b7ebdaf5fcd75dceedf6967d0761e56eca1 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Sat, 17 Jun 2023 18:25:45 +0000 Subject: [PATCH 0197/3445] iommu: rockchip: Fix directory table address encoding The physical address to the directory table is currently encoded using the following bit layout for IOMMU v2. 31:12 - Address bit 31:0 11: 4 - Address bit 39:32 This is also the bit layout used by the vendor kernel. However, testing has shown that addresses to the directory/page tables and memory pages are all encoded using the same bit layout. IOMMU v1: 31:12 - Address bit 31:0 IOMMU v2: 31:12 - Address bit 31:0 11: 8 - Address bit 35:32 7: 4 - Address bit 39:36 Change to use the mk_dtentries ops to encode the directory table address correctly. The value written to DTE_ADDR may include the valid bit set, a bit that is ignored and DTE_ADDR reg read it back as 0. This also update the bit layout comment for the page address and the number of nybbles that are read back for DTE_ADDR comment. These changes render the dte_addr_phys and dma_addr_dte ops unused and is removed. Fixes: 227014b33f62 ("iommu: rockchip: Add internal ops to handle variants") Fixes: c55356c534aa ("iommu: rockchip: Add support for iommu v2") Fixes: c987b65a574f ("iommu/rockchip: Fix physical address decoding") Signed-off-by: Jonas Karlman Reviewed-by: Robin Murphy Link: https://lore.kernel.org/r/20230617182540.3091374-2-jonas@kwiboo.se Signed-off-by: Joerg Roedel --- drivers/iommu/rockchip-iommu.c | 43 ++++------------------------------ 1 file changed, 5 insertions(+), 38 deletions(-) diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index 4054030c32379..ae42959bc4905 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -98,8 +98,6 @@ struct rk_iommu_ops { phys_addr_t (*pt_address)(u32 dte); u32 (*mk_dtentries)(dma_addr_t pt_dma); u32 (*mk_ptentries)(phys_addr_t page, int prot); - phys_addr_t (*dte_addr_phys)(u32 addr); - u32 (*dma_addr_dte)(dma_addr_t dt_dma); u64 dma_bit_mask; }; @@ -278,8 +276,8 @@ static u32 rk_mk_pte(phys_addr_t page, int prot) /* * In v2: * 31:12 - Page address bit 31:0 - * 11:9 - Page address bit 34:32 - * 8:4 - Page address bit 39:35 + * 11: 8 - Page address bit 35:32 + * 7: 4 - Page address bit 39:36 * 3 - Security * 2 - Writable * 1 - Readable @@ -506,7 +504,7 @@ static int rk_iommu_force_reset(struct rk_iommu *iommu) /* * Check if register DTE_ADDR is working by writing DTE_ADDR_DUMMY - * and verifying that upper 5 nybbles are read back. + * and verifying that upper 5 (v1) or 7 (v2) nybbles are read back. */ for (i = 0; i < iommu->num_mmu; i++) { dte_addr = rk_ops->pt_address(DTE_ADDR_DUMMY); @@ -531,33 +529,6 @@ static int rk_iommu_force_reset(struct rk_iommu *iommu) return 0; } -static inline phys_addr_t rk_dte_addr_phys(u32 addr) -{ - return (phys_addr_t)addr; -} - -static inline u32 rk_dma_addr_dte(dma_addr_t dt_dma) -{ - return dt_dma; -} - -#define DT_HI_MASK GENMASK_ULL(39, 32) -#define DTE_BASE_HI_MASK GENMASK(11, 4) -#define DT_SHIFT 28 - -static inline phys_addr_t rk_dte_addr_phys_v2(u32 addr) -{ - u64 addr64 = addr; - return (phys_addr_t)(addr64 & RK_DTE_PT_ADDRESS_MASK) | - ((addr64 & DTE_BASE_HI_MASK) << DT_SHIFT); -} - -static inline u32 rk_dma_addr_dte_v2(dma_addr_t dt_dma) -{ - return (dt_dma & RK_DTE_PT_ADDRESS_MASK) | - ((dt_dma & DT_HI_MASK) >> DT_SHIFT); -} - static void log_iova(struct rk_iommu *iommu, int index, dma_addr_t iova) { void __iomem *base = iommu->bases[index]; @@ -577,7 +548,7 @@ static void log_iova(struct rk_iommu *iommu, int index, dma_addr_t iova) page_offset = rk_iova_page_offset(iova); mmu_dte_addr = rk_iommu_read(base, RK_MMU_DTE_ADDR); - mmu_dte_addr_phys = rk_ops->dte_addr_phys(mmu_dte_addr); + mmu_dte_addr_phys = rk_ops->pt_address(mmu_dte_addr); dte_addr_phys = mmu_dte_addr_phys + (4 * dte_index); dte_addr = phys_to_virt(dte_addr_phys); @@ -967,7 +938,7 @@ static int rk_iommu_enable(struct rk_iommu *iommu) for (i = 0; i < iommu->num_mmu; i++) { rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR, - rk_ops->dma_addr_dte(rk_domain->dt_dma)); + rk_ops->mk_dtentries(rk_domain->dt_dma)); rk_iommu_base_command(iommu->bases[i], RK_MMU_CMD_ZAP_CACHE); rk_iommu_write(iommu->bases[i], RK_MMU_INT_MASK, RK_MMU_IRQ_MASK); } @@ -1405,8 +1376,6 @@ static struct rk_iommu_ops iommu_data_ops_v1 = { .pt_address = &rk_dte_pt_address, .mk_dtentries = &rk_mk_dte, .mk_ptentries = &rk_mk_pte, - .dte_addr_phys = &rk_dte_addr_phys, - .dma_addr_dte = &rk_dma_addr_dte, .dma_bit_mask = DMA_BIT_MASK(32), }; @@ -1414,8 +1383,6 @@ static struct rk_iommu_ops iommu_data_ops_v2 = { .pt_address = &rk_dte_pt_address_v2, .mk_dtentries = &rk_mk_dte_v2, .mk_ptentries = &rk_mk_pte_v2, - .dte_addr_phys = &rk_dte_addr_phys_v2, - .dma_addr_dte = &rk_dma_addr_dte_v2, .dma_bit_mask = DMA_BIT_MASK(40), }; -- GitLab From 2a7e6400f72b9963cbaaac8a60ccc54d2b8c0541 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Sat, 17 Jun 2023 18:25:47 +0000 Subject: [PATCH 0198/3445] iommu: rockchip: Allocate tables from all available memory for IOMMU v2 IOMMU v2 found in newer Rockchip SoCs, e.g. RK356x and RK3588, support placing directory and page tables in up to 40-bit addressable physical memory. Remove the use of GFP_DMA32 flag for IOMMU v2 now that the physical address to the directory table is correctly written to DTE_ADDR. Signed-off-by: Jonas Karlman Reviewed-by: Robin Murphy Link: https://lore.kernel.org/r/20230617182540.3091374-3-jonas@kwiboo.se Signed-off-by: Joerg Roedel --- drivers/iommu/rockchip-iommu.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index ae42959bc4905..8ff69fbf9f65d 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -99,6 +99,7 @@ struct rk_iommu_ops { u32 (*mk_dtentries)(dma_addr_t pt_dma); u32 (*mk_ptentries)(phys_addr_t page, int prot); u64 dma_bit_mask; + gfp_t gfp_flags; }; struct rk_iommu { @@ -727,7 +728,7 @@ static u32 *rk_dte_get_page_table(struct rk_iommu_domain *rk_domain, if (rk_dte_is_pt_valid(dte)) goto done; - page_table = (u32 *)get_zeroed_page(GFP_ATOMIC | GFP_DMA32); + page_table = (u32 *)get_zeroed_page(GFP_ATOMIC | rk_ops->gfp_flags); if (!page_table) return ERR_PTR(-ENOMEM); @@ -1076,7 +1077,7 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type) * Each level1 (dt) and level2 (pt) table has 1024 4-byte entries. * Allocate one 4 KiB page for each table. */ - rk_domain->dt = (u32 *)get_zeroed_page(GFP_KERNEL | GFP_DMA32); + rk_domain->dt = (u32 *)get_zeroed_page(GFP_KERNEL | rk_ops->gfp_flags); if (!rk_domain->dt) goto err_free_domain; @@ -1377,6 +1378,7 @@ static struct rk_iommu_ops iommu_data_ops_v1 = { .mk_dtentries = &rk_mk_dte, .mk_ptentries = &rk_mk_pte, .dma_bit_mask = DMA_BIT_MASK(32), + .gfp_flags = GFP_DMA32, }; static struct rk_iommu_ops iommu_data_ops_v2 = { @@ -1384,6 +1386,7 @@ static struct rk_iommu_ops iommu_data_ops_v2 = { .mk_dtentries = &rk_mk_dte_v2, .mk_ptentries = &rk_mk_pte_v2, .dma_bit_mask = DMA_BIT_MASK(40), + .gfp_flags = 0, }; static const struct of_device_id rk_iommu_dt_ids[] = { -- GitLab From 386ae59bd7db4eafc74bdfdcf60182c2171aea2a Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Wed, 28 Jun 2023 05:16:23 +0000 Subject: [PATCH 0199/3445] iommu/amd: Generalize log overflow handling Each IOMMU has three log buffers (Event, GA and PPR log). Once a buffer becomes full, IOMMU generates an interrupt with the corresponding overflow status bit, and stop processing the log. To handle an overflow, the IOMMU driver needs to disable the log, clear the overflow status bit, and re-enable the log. This procedure is same among all types of log buffer except it uses different overflow status bit and enabling bit. Hence, to consolidate the log buffer restarting logic, introduce a helper function amd_iommu_restart_log(), which caller can specify parameters specific for each type of log buffer. Also rename MMIO_STATUS_EVT_OVERFLOW_INT_MASK as MMIO_STATUS_EVT_OVERFLOW_MASK. Reviewed-by: Jerry Snitselaar Reviewed-by: Suravee Suthikulpanit Reviewed-by: Joao Martins Signed-off-by: Vasant Hegde Link: https://lore.kernel.org/r/20230628051624.5792-2-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/amd_iommu_types.h | 3 +- drivers/iommu/amd/init.c | 51 ++++++++++++++++++----------- drivers/iommu/amd/iommu.c | 4 +-- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index dc1db61679279..7c436ba2a0a23 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -120,9 +120,10 @@ #define PASID_MASK 0x0000ffff /* MMIO status bits */ -#define MMIO_STATUS_EVT_OVERFLOW_INT_MASK BIT(0) +#define MMIO_STATUS_EVT_OVERFLOW_MASK BIT(0) #define MMIO_STATUS_EVT_INT_MASK BIT(1) #define MMIO_STATUS_COM_WAIT_INT_MASK BIT(2) +#define MMIO_STATUS_EVT_RUN_MASK BIT(3) #define MMIO_STATUS_PPR_INT_MASK BIT(6) #define MMIO_STATUS_GALOG_RUN_MASK BIT(8) #define MMIO_STATUS_GALOG_OVERFLOW_MASK BIT(9) diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index ea0f1ab941783..7fab6ecb62958 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -752,38 +752,51 @@ static int __init alloc_command_buffer(struct amd_iommu *iommu) return iommu->cmd_buf ? 0 : -ENOMEM; } +/* + * Interrupt handler has processed all pending events and adjusted head + * and tail pointer. Reset overflow mask and restart logging again. + */ +static void amd_iommu_restart_log(struct amd_iommu *iommu, const char *evt_type, + u8 cntrl_intr, u8 cntrl_log, + u32 status_run_mask, u32 status_overflow_mask) +{ + u32 status; + + status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET); + if (status & status_run_mask) + return; + + pr_info_ratelimited("IOMMU %s log restarting\n", evt_type); + + iommu_feature_disable(iommu, cntrl_log); + iommu_feature_disable(iommu, cntrl_intr); + + writel(status_overflow_mask, iommu->mmio_base + MMIO_STATUS_OFFSET); + + iommu_feature_enable(iommu, cntrl_intr); + iommu_feature_enable(iommu, cntrl_log); +} + /* * This function restarts event logging in case the IOMMU experienced * an event log buffer overflow. */ void amd_iommu_restart_event_logging(struct amd_iommu *iommu) { - iommu_feature_disable(iommu, CONTROL_EVT_LOG_EN); - iommu_feature_enable(iommu, CONTROL_EVT_LOG_EN); + amd_iommu_restart_log(iommu, "Event", CONTROL_EVT_INT_EN, + CONTROL_EVT_LOG_EN, MMIO_STATUS_EVT_RUN_MASK, + MMIO_STATUS_EVT_OVERFLOW_MASK); } /* * This function restarts event logging in case the IOMMU experienced - * an GA log overflow. + * GA log overflow. */ void amd_iommu_restart_ga_log(struct amd_iommu *iommu) { - u32 status; - - status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET); - if (status & MMIO_STATUS_GALOG_RUN_MASK) - return; - - pr_info_ratelimited("IOMMU GA Log restarting\n"); - - iommu_feature_disable(iommu, CONTROL_GALOG_EN); - iommu_feature_disable(iommu, CONTROL_GAINT_EN); - - writel(MMIO_STATUS_GALOG_OVERFLOW_MASK, - iommu->mmio_base + MMIO_STATUS_OFFSET); - - iommu_feature_enable(iommu, CONTROL_GAINT_EN); - iommu_feature_enable(iommu, CONTROL_GALOG_EN); + amd_iommu_restart_log(iommu, "GA", CONTROL_GAINT_EN, + CONTROL_GALOG_EN, MMIO_STATUS_GALOG_RUN_MASK, + MMIO_STATUS_GALOG_OVERFLOW_MASK); } /* diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index c3b58a8389b9b..86c0ae34373b5 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -842,7 +842,7 @@ amd_iommu_set_pci_msi_domain(struct device *dev, struct amd_iommu *iommu) { } #endif /* !CONFIG_IRQ_REMAP */ #define AMD_IOMMU_INT_MASK \ - (MMIO_STATUS_EVT_OVERFLOW_INT_MASK | \ + (MMIO_STATUS_EVT_OVERFLOW_MASK | \ MMIO_STATUS_EVT_INT_MASK | \ MMIO_STATUS_PPR_INT_MASK | \ MMIO_STATUS_GALOG_OVERFLOW_MASK | \ @@ -881,7 +881,7 @@ irqreturn_t amd_iommu_int_thread(int irq, void *data) } #endif - if (status & MMIO_STATUS_EVT_OVERFLOW_INT_MASK) { + if (status & MMIO_STATUS_EVT_OVERFLOW_MASK) { pr_info_ratelimited("IOMMU event log overflow\n"); amd_iommu_restart_event_logging(iommu); } -- GitLab From 274c2218b8b29ea2e0404f97d52040deb16d42dd Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Wed, 28 Jun 2023 05:16:24 +0000 Subject: [PATCH 0200/3445] iommu/amd: Handle PPR log overflow Some ATS-capable peripherals can issue requests to the processor to service peripheral page requests using PCIe PRI (the Page Request Interface). IOMMU supports PRI using PPR log buffer. IOMMU writes PRI request to PPR log buffer and sends PPR interrupt to host. When there is no space in the PPR log buffer (PPR log overflow) it will set PprOverflow bit in 'MMIO Offset 2020h IOMMU Status Register'. When this happens PPR log needs to be restarted as specified in IOMMU spec [1] section 2.6.2. When handling the event it just resumes the PPR log without resizing (similar to the way event and GA log overflow is handled). Failing to handle PPR overflow means device may not work properly as IOMMU stops processing new PPR events from device. [1] https://www.amd.com/system/files/TechDocs/48882_3.07_PUB.pdf Reviewed-by: Jerry Snitselaar Reviewed-by: Suravee Suthikulpanit Reviewed-by: Joao Martins Signed-off-by: Vasant Hegde Link: https://lore.kernel.org/r/20230628051624.5792-3-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/amd_iommu.h | 1 + drivers/iommu/amd/amd_iommu_types.h | 2 ++ drivers/iommu/amd/init.c | 11 +++++++++++ drivers/iommu/amd/iommu.c | 9 ++++++++- 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h index 0c35018239cec..8c61c19dabc4f 100644 --- a/drivers/iommu/amd/amd_iommu.h +++ b/drivers/iommu/amd/amd_iommu.h @@ -16,6 +16,7 @@ irqreturn_t amd_iommu_int_handler(int irq, void *data); void amd_iommu_apply_erratum_63(struct amd_iommu *iommu, u16 devid); void amd_iommu_restart_event_logging(struct amd_iommu *iommu); void amd_iommu_restart_ga_log(struct amd_iommu *iommu); +void amd_iommu_restart_ppr_log(struct amd_iommu *iommu); int amd_iommu_init_devices(void); void amd_iommu_uninit_devices(void); void amd_iommu_init_notifier(void); diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index 7c436ba2a0a23..c8150eaf5c0e2 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -124,7 +124,9 @@ #define MMIO_STATUS_EVT_INT_MASK BIT(1) #define MMIO_STATUS_COM_WAIT_INT_MASK BIT(2) #define MMIO_STATUS_EVT_RUN_MASK BIT(3) +#define MMIO_STATUS_PPR_OVERFLOW_MASK BIT(5) #define MMIO_STATUS_PPR_INT_MASK BIT(6) +#define MMIO_STATUS_PPR_RUN_MASK BIT(7) #define MMIO_STATUS_GALOG_RUN_MASK BIT(8) #define MMIO_STATUS_GALOG_OVERFLOW_MASK BIT(9) #define MMIO_STATUS_GALOG_INT_MASK BIT(10) diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index 7fab6ecb62958..e78d7c4f41bd4 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -799,6 +799,17 @@ void amd_iommu_restart_ga_log(struct amd_iommu *iommu) MMIO_STATUS_GALOG_OVERFLOW_MASK); } +/* + * This function restarts ppr logging in case the IOMMU experienced + * PPR log overflow. + */ +void amd_iommu_restart_ppr_log(struct amd_iommu *iommu) +{ + amd_iommu_restart_log(iommu, "PPR", CONTROL_PPRINT_EN, + CONTROL_PPRLOG_EN, MMIO_STATUS_PPR_RUN_MASK, + MMIO_STATUS_PPR_OVERFLOW_MASK); +} + /* * This function resets the command buffer if the IOMMU stopped fetching * commands from it. diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 86c0ae34373b5..f8316901a1780 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -844,6 +844,7 @@ amd_iommu_set_pci_msi_domain(struct device *dev, struct amd_iommu *iommu) { } #define AMD_IOMMU_INT_MASK \ (MMIO_STATUS_EVT_OVERFLOW_MASK | \ MMIO_STATUS_EVT_INT_MASK | \ + MMIO_STATUS_PPR_OVERFLOW_MASK | \ MMIO_STATUS_PPR_INT_MASK | \ MMIO_STATUS_GALOG_OVERFLOW_MASK | \ MMIO_STATUS_GALOG_INT_MASK) @@ -863,11 +864,17 @@ irqreturn_t amd_iommu_int_thread(int irq, void *data) iommu_poll_events(iommu); } - if (status & MMIO_STATUS_PPR_INT_MASK) { + if (status & (MMIO_STATUS_PPR_INT_MASK | + MMIO_STATUS_PPR_OVERFLOW_MASK)) { pr_devel("Processing IOMMU PPR Log\n"); iommu_poll_ppr_log(iommu); } + if (status & MMIO_STATUS_PPR_OVERFLOW_MASK) { + pr_info_ratelimited("IOMMU PPR log overflow\n"); + amd_iommu_restart_ppr_log(iommu); + } + #ifdef CONFIG_IRQ_REMAP if (status & (MMIO_STATUS_GALOG_INT_MASK | MMIO_STATUS_GALOG_OVERFLOW_MASK)) { -- GitLab From 2379f3485239095b8782353c2431f3c97c275986 Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Wed, 28 Jun 2023 05:32:21 +0000 Subject: [PATCH 0201/3445] iommu/amd: Refactor IOMMU interrupt handling logic for Event, PPR, and GA logs The AMD IOMMU has three log buffers (i.e. Event, PPR, and GA). The IOMMU driver processes these log entries when it receive an IOMMU interrupt. Then, it needs to clear the corresponding interrupt status bits. Also, when an overflow occurs, it needs to handle the log overflow by clearing the specific overflow status bit and restart the log. Since, logic for handling these logs is the same, refactor the code into a helper function called amd_iommu_handle_irq(), which handles the steps described. Then, reuse it for all types of log. Reviewed-by: Suravee Suthikulpanit Signed-off-by: Vasant Hegde Reviewed-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20230628053222.5962-2-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/amd_iommu.h | 3 ++ drivers/iommu/amd/iommu.c | 93 +++++++++++++++++++---------------- 2 files changed, 53 insertions(+), 43 deletions(-) diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h index 8c61c19dabc4f..f23ad6043f04b 100644 --- a/drivers/iommu/amd/amd_iommu.h +++ b/drivers/iommu/amd/amd_iommu.h @@ -12,6 +12,9 @@ #include "amd_iommu_types.h" irqreturn_t amd_iommu_int_thread(int irq, void *data); +irqreturn_t amd_iommu_int_thread_evtlog(int irq, void *data); +irqreturn_t amd_iommu_int_thread_pprlog(int irq, void *data); +irqreturn_t amd_iommu_int_thread_galog(int irq, void *data); irqreturn_t amd_iommu_int_handler(int irq, void *data); void amd_iommu_apply_erratum_63(struct amd_iommu *iommu, u16 devid); void amd_iommu_restart_event_logging(struct amd_iommu *iommu); diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index f8316901a1780..56b6cf8bf03fb 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -841,57 +841,27 @@ static inline void amd_iommu_set_pci_msi_domain(struct device *dev, struct amd_iommu *iommu) { } #endif /* !CONFIG_IRQ_REMAP */ -#define AMD_IOMMU_INT_MASK \ - (MMIO_STATUS_EVT_OVERFLOW_MASK | \ - MMIO_STATUS_EVT_INT_MASK | \ - MMIO_STATUS_PPR_OVERFLOW_MASK | \ - MMIO_STATUS_PPR_INT_MASK | \ - MMIO_STATUS_GALOG_OVERFLOW_MASK | \ - MMIO_STATUS_GALOG_INT_MASK) - -irqreturn_t amd_iommu_int_thread(int irq, void *data) +static void amd_iommu_handle_irq(void *data, const char *evt_type, + u32 int_mask, u32 overflow_mask, + void (*int_handler)(struct amd_iommu *), + void (*overflow_handler)(struct amd_iommu *)) { struct amd_iommu *iommu = (struct amd_iommu *) data; u32 status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET); + u32 mask = int_mask | overflow_mask; - while (status & AMD_IOMMU_INT_MASK) { + while (status & mask) { /* Enable interrupt sources again */ - writel(AMD_IOMMU_INT_MASK, - iommu->mmio_base + MMIO_STATUS_OFFSET); - - if (status & MMIO_STATUS_EVT_INT_MASK) { - pr_devel("Processing IOMMU Event Log\n"); - iommu_poll_events(iommu); - } - - if (status & (MMIO_STATUS_PPR_INT_MASK | - MMIO_STATUS_PPR_OVERFLOW_MASK)) { - pr_devel("Processing IOMMU PPR Log\n"); - iommu_poll_ppr_log(iommu); - } - - if (status & MMIO_STATUS_PPR_OVERFLOW_MASK) { - pr_info_ratelimited("IOMMU PPR log overflow\n"); - amd_iommu_restart_ppr_log(iommu); - } - -#ifdef CONFIG_IRQ_REMAP - if (status & (MMIO_STATUS_GALOG_INT_MASK | - MMIO_STATUS_GALOG_OVERFLOW_MASK)) { - pr_devel("Processing IOMMU GA Log\n"); - iommu_poll_ga_log(iommu); - } + writel(mask, iommu->mmio_base + MMIO_STATUS_OFFSET); - if (status & MMIO_STATUS_GALOG_OVERFLOW_MASK) { - pr_info_ratelimited("IOMMU GA Log overflow\n"); - amd_iommu_restart_ga_log(iommu); + if (int_handler) { + pr_devel("Processing IOMMU (ivhd%d) %s Log\n", + iommu->index, evt_type); + int_handler(iommu); } -#endif - if (status & MMIO_STATUS_EVT_OVERFLOW_MASK) { - pr_info_ratelimited("IOMMU event log overflow\n"); - amd_iommu_restart_event_logging(iommu); - } + if ((status & overflow_mask) && overflow_handler) + overflow_handler(iommu); /* * Hardware bug: ERBT1312 @@ -908,6 +878,43 @@ irqreturn_t amd_iommu_int_thread(int irq, void *data) */ status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET); } +} + +irqreturn_t amd_iommu_int_thread_evtlog(int irq, void *data) +{ + amd_iommu_handle_irq(data, "Evt", MMIO_STATUS_EVT_INT_MASK, + MMIO_STATUS_EVT_OVERFLOW_MASK, + iommu_poll_events, amd_iommu_restart_event_logging); + + return IRQ_HANDLED; +} + +irqreturn_t amd_iommu_int_thread_pprlog(int irq, void *data) +{ + amd_iommu_handle_irq(data, "PPR", MMIO_STATUS_PPR_INT_MASK, + MMIO_STATUS_PPR_OVERFLOW_MASK, + iommu_poll_ppr_log, amd_iommu_restart_ppr_log); + + return IRQ_HANDLED; +} + +irqreturn_t amd_iommu_int_thread_galog(int irq, void *data) +{ +#ifdef CONFIG_IRQ_REMAP + amd_iommu_handle_irq(data, "GA", MMIO_STATUS_GALOG_INT_MASK, + MMIO_STATUS_GALOG_OVERFLOW_MASK, + iommu_poll_ga_log, amd_iommu_restart_ga_log); +#endif + + return IRQ_HANDLED; +} + +irqreturn_t amd_iommu_int_thread(int irq, void *data) +{ + amd_iommu_int_thread_evtlog(irq, data); + amd_iommu_int_thread_pprlog(irq, data); + amd_iommu_int_thread_galog(irq, data); + return IRQ_HANDLED; } -- GitLab From e5ebd90d1b5cbfa0df9b911cd3f24c1bb84c05dd Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Wed, 28 Jun 2023 05:32:22 +0000 Subject: [PATCH 0202/3445] iommu/amd: Enable separate interrupt for PPR and GA log AMD IOMMU has three log buffers (i.e. Event, PPR, and GA). These logs can be configured to generate different interrupts when an entry is inserted into a log buffer. However, current implementation share single interrupt to handle all three logs. With increasing usages of the GA (for IOMMU AVIC) and PPR logs (for IOMMUv2 APIs and SVA), interrupt sharing could potentially become performance bottleneck. Hence, separate IOMMU interrupt into use three separate vectors and irq threads with corresponding name, which will be displayed in the /proc/interrupts as "AMD-Vi-[Evt/PPR/GA]", where "x" is an IOMMU id. Note that this patch changes interrupt handling only in IOMMU x2apic mode (MMIO 0x18[IntCapXTEn]=1). In legacy mode it will continue to use single MSI interrupt. Signed-off-by: Vasant Hegde Reviewed-by: Alexey Kardashevskiy Reviewed-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20230628053222.5962-3-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/amd_iommu_types.h | 9 ++++++ drivers/iommu/amd/init.c | 50 ++++++++++++++++++++++------- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index c8150eaf5c0e2..781ab9c2ea70d 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -705,12 +705,21 @@ struct amd_iommu { /* event buffer virtual address */ u8 *evt_buf; + /* Name for event log interrupt */ + unsigned char evt_irq_name[16]; + /* Base of the PPR log, if present */ u8 *ppr_log; + /* Name for PPR log interrupt */ + unsigned char ppr_irq_name[16]; + /* Base of the GA log, if present */ u8 *ga_log; + /* Name for GA log interrupt */ + unsigned char ga_irq_name[16]; + /* Tail of the GA log, if present */ u8 *ga_log_tail; diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index e78d7c4f41bd4..30f09e786f7b9 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -2335,6 +2335,7 @@ static int intcapxt_irqdomain_alloc(struct irq_domain *domain, unsigned int virq struct irq_data *irqd = irq_domain_get_irq_data(domain, i); irqd->chip = &intcapxt_controller; + irqd->hwirq = info->hwirq; irqd->chip_data = info->data; __irq_set_handler(i, handle_edge_irq, 0, "edge"); } @@ -2361,22 +2362,14 @@ static void intcapxt_unmask_irq(struct irq_data *irqd) xt.destid_0_23 = cfg->dest_apicid & GENMASK(23, 0); xt.destid_24_31 = cfg->dest_apicid >> 24; - /** - * Current IOMMU implementation uses the same IRQ for all - * 3 IOMMU interrupts. - */ - writeq(xt.capxt, iommu->mmio_base + MMIO_INTCAPXT_EVT_OFFSET); - writeq(xt.capxt, iommu->mmio_base + MMIO_INTCAPXT_PPR_OFFSET); - writeq(xt.capxt, iommu->mmio_base + MMIO_INTCAPXT_GALOG_OFFSET); + writeq(xt.capxt, iommu->mmio_base + irqd->hwirq); } static void intcapxt_mask_irq(struct irq_data *irqd) { struct amd_iommu *iommu = irqd->chip_data; - writeq(0, iommu->mmio_base + MMIO_INTCAPXT_EVT_OFFSET); - writeq(0, iommu->mmio_base + MMIO_INTCAPXT_PPR_OFFSET); - writeq(0, iommu->mmio_base + MMIO_INTCAPXT_GALOG_OFFSET); + writeq(0, iommu->mmio_base + irqd->hwirq); } @@ -2439,7 +2432,8 @@ static struct irq_domain *iommu_get_irqdomain(void) return iommu_irqdomain; } -static int iommu_setup_intcapxt(struct amd_iommu *iommu) +static int __iommu_setup_intcapxt(struct amd_iommu *iommu, const char *devname, + int hwirq, irq_handler_t thread_fn) { struct irq_domain *domain; struct irq_alloc_info info; @@ -2453,6 +2447,7 @@ static int iommu_setup_intcapxt(struct amd_iommu *iommu) init_irq_alloc_info(&info, NULL); info.type = X86_IRQ_ALLOC_TYPE_AMDVI; info.data = iommu; + info.hwirq = hwirq; irq = irq_domain_alloc_irqs(domain, 1, node, &info); if (irq < 0) { @@ -2461,7 +2456,7 @@ static int iommu_setup_intcapxt(struct amd_iommu *iommu) } ret = request_threaded_irq(irq, amd_iommu_int_handler, - amd_iommu_int_thread, 0, "AMD-Vi", iommu); + thread_fn, 0, devname, iommu); if (ret) { irq_domain_free_irqs(irq, 1); irq_domain_remove(domain); @@ -2471,6 +2466,37 @@ static int iommu_setup_intcapxt(struct amd_iommu *iommu) return 0; } +static int iommu_setup_intcapxt(struct amd_iommu *iommu) +{ + int ret; + + snprintf(iommu->evt_irq_name, sizeof(iommu->evt_irq_name), + "AMD-Vi%d-Evt", iommu->index); + ret = __iommu_setup_intcapxt(iommu, iommu->evt_irq_name, + MMIO_INTCAPXT_EVT_OFFSET, + amd_iommu_int_thread_evtlog); + if (ret) + return ret; + + snprintf(iommu->ppr_irq_name, sizeof(iommu->ppr_irq_name), + "AMD-Vi%d-PPR", iommu->index); + ret = __iommu_setup_intcapxt(iommu, iommu->ppr_irq_name, + MMIO_INTCAPXT_PPR_OFFSET, + amd_iommu_int_thread_pprlog); + if (ret) + return ret; + +#ifdef CONFIG_IRQ_REMAP + snprintf(iommu->ga_irq_name, sizeof(iommu->ga_irq_name), + "AMD-Vi%d-GA", iommu->index); + ret = __iommu_setup_intcapxt(iommu, iommu->ga_irq_name, + MMIO_INTCAPXT_GALOG_OFFSET, + amd_iommu_int_thread_galog); +#endif + + return ret; +} + static int iommu_init_irq(struct amd_iommu *iommu) { int ret; -- GitLab From 7827a2689e79bcd3096b4b49b8a8beb8574fd4aa Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Wed, 28 Jun 2023 05:45:52 +0000 Subject: [PATCH 0203/3445] iommu/amd: Disable PPR log/interrupt in iommu_disable() Similar to other logs, disable PPR log/interrupt in iommu_disable() path. Reviewed-by: Suravee Suthikulpanit Signed-off-by: Vasant Hegde Reviewed-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20230628054554.6131-2-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/init.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index 30f09e786f7b9..94c91b6ee603d 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -483,6 +483,10 @@ static void iommu_disable(struct amd_iommu *iommu) iommu_feature_disable(iommu, CONTROL_GALOG_EN); iommu_feature_disable(iommu, CONTROL_GAINT_EN); + /* Disable IOMMU PPR logging */ + iommu_feature_disable(iommu, CONTROL_PPRLOG_EN); + iommu_feature_disable(iommu, CONTROL_PPRINT_EN); + /* Disable IOMMU hardware itself */ iommu_feature_disable(iommu, CONTROL_IOMMU_EN); -- GitLab From f52c895a2de8697108c6385e9695061585690dc8 Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Wed, 28 Jun 2023 05:45:53 +0000 Subject: [PATCH 0204/3445] iommu/amd: Consolidate PPR log enablement Move PPR log interrupt bit setting to iommu_enable_ppr_log(). Also rearrange iommu_enable_ppr_log() such that PPREn bit is enabled before enabling PPRLog and PPRInt bits. So that when PPRLog bit is set it will clear the PPRLogOverflow bit and sets the PPRLogRun bit in the IOMMU Status Register [MMIO Offset 2020h]. Reviewed-by: Suravee Suthikulpanit Signed-off-by: Vasant Hegde Reviewed-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20230628054554.6131-3-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index 94c91b6ee603d..f26c077eb9ea1 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -934,6 +934,8 @@ static void iommu_enable_ppr_log(struct amd_iommu *iommu) if (iommu->ppr_log == NULL) return; + iommu_feature_enable(iommu, CONTROL_PPR_EN); + entry = iommu_virt_to_phys(iommu->ppr_log) | PPR_LOG_SIZE_512; memcpy_toio(iommu->mmio_base + MMIO_PPR_LOG_OFFSET, @@ -944,7 +946,7 @@ static void iommu_enable_ppr_log(struct amd_iommu *iommu) writel(0x00, iommu->mmio_base + MMIO_PPR_TAIL_OFFSET); iommu_feature_enable(iommu, CONTROL_PPRLOG_EN); - iommu_feature_enable(iommu, CONTROL_PPR_EN); + iommu_feature_enable(iommu, CONTROL_PPRINT_EN); } static void __init free_ppr_log(struct amd_iommu *iommu) @@ -2526,8 +2528,6 @@ enable_faults: iommu_feature_enable(iommu, CONTROL_EVT_INT_EN); - if (iommu->ppr_log != NULL) - iommu_feature_enable(iommu, CONTROL_PPRINT_EN); return 0; } -- GitLab From a48130e92f1c86638295a53d1735dfed7f55a2c4 Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Wed, 28 Jun 2023 05:45:54 +0000 Subject: [PATCH 0205/3445] iommu/amd: Enable PPR/GA interrupt after interrupt handler setup Current code enables PPR and GA interrupts before setting up the interrupt handler (in state_next()). Make sure interrupt handler is in place before enabling these interrupt. amd_iommu_enable_interrupts() gets called in normal boot, kdump as well as in suspend/resume path. Hence moving interrupt enablement to this function works fine. Reviewed-by: Suravee Suthikulpanit Signed-off-by: Vasant Hegde Reviewed-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20230628054554.6131-4-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/init.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index f26c077eb9ea1..45efb7e5d7254 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -2943,8 +2943,6 @@ static void enable_iommus_vapic(void) static void enable_iommus(void) { early_enable_iommus(); - enable_iommus_vapic(); - enable_iommus_v2(); } static void disable_iommus(void) @@ -3208,6 +3206,13 @@ static int amd_iommu_enable_interrupts(void) goto out; } + /* + * Interrupt handler is ready to process interrupts. Enable + * PPR and GA log interrupt for all IOMMUs. + */ + enable_iommus_vapic(); + enable_iommus_v2(); + out: return ret; } @@ -3287,8 +3292,6 @@ static int __init state_next(void) register_syscore_ops(&amd_iommu_syscore_ops); ret = amd_iommu_init_pci(); init_state = ret ? IOMMU_INIT_ERROR : IOMMU_PCI_INIT; - enable_iommus_vapic(); - enable_iommus_v2(); break; case IOMMU_PCI_INIT: ret = amd_iommu_enable_interrupts(); -- GitLab From ceddae22cd08ba9f52a995cfb573fee89fa4afc4 Mon Sep 17 00:00:00 2001 From: Miaohe Lin Date: Thu, 13 Jul 2023 19:59:38 +0800 Subject: [PATCH 0206/3445] cgroup: remove obsolete comment above struct cgroupstats There's no flag in the delay accounting structure indicates that the task is waiting on IO since commit 1193829da1a6 ("delayacct: cleanup flags in struct task_delay_info and functions use it"). So remove the comment. Signed-off-by: Miaohe Lin Signed-off-by: Tejun Heo --- include/uapi/linux/cgroupstats.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/uapi/linux/cgroupstats.h b/include/uapi/linux/cgroupstats.h index aa306e4cd6c1f..80b2c85944806 100644 --- a/include/uapi/linux/cgroupstats.h +++ b/include/uapi/linux/cgroupstats.h @@ -24,8 +24,6 @@ * basis. This data is shared using taskstats. * * Most of these states are derived by looking at the task->state value - * For the nr_io_wait state, a flag in the delay accounting structure - * indicates that the task is waiting on IO * * Each member is aligned to a 8 byte boundary. */ -- GitLab From b798f7729ca66a620242435f0d325aefe0a13b31 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Thu, 13 Jul 2023 18:44:22 +0800 Subject: [PATCH 0207/3445] mtd: nand: omap: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230713104422.29222-1-frank.li@vivo.com --- drivers/mtd/nand/onenand/onenand_omap2.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/onenand/onenand_omap2.c b/drivers/mtd/nand/onenand/onenand_omap2.c index ff7af98604df2..904df2d1538ee 100644 --- a/drivers/mtd/nand/onenand/onenand_omap2.c +++ b/drivers/mtd/nand/onenand/onenand_omap2.c @@ -467,12 +467,6 @@ static int omap2_onenand_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "error getting memory resource\n"); - return -EINVAL; - } - r = of_property_read_u32(np, "reg", &val); if (r) { dev_err(dev, "reg not found in DT\n"); @@ -486,11 +480,11 @@ static int omap2_onenand_probe(struct platform_device *pdev) init_completion(&c->irq_done); init_completion(&c->dma_done); c->gpmc_cs = val; - c->phys_base = res->start; - c->onenand.base = devm_ioremap_resource(dev, res); + c->onenand.base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(c->onenand.base)) return PTR_ERR(c->onenand.base); + c->phys_base = res->start; c->int_gpiod = devm_gpiod_get_optional(dev, "int", GPIOD_IN); if (IS_ERR(c->int_gpiod)) { -- GitLab From 89550beb098e04b951df079483fb064eafc0e5fa Mon Sep 17 00:00:00 2001 From: Md Sadre Alam Date: Mon, 10 Jul 2023 11:14:39 +0530 Subject: [PATCH 0208/3445] mtd: rawnand: qcom: Implement exec_op() Implement exec_op() so we can later get rid of the legacy interface implementation. Co-developed-by: Sricharan Ramabadhran Signed-off-by: Sricharan Ramabadhran Signed-off-by: Md Sadre Alam Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230710054440.23297-1-quic_mdalam@quicinc.com --- drivers/mtd/nand/raw/qcom_nandc.c | 534 +++++++++++++++++++++++++++++- 1 file changed, 531 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 72d6168d8a1be..852c6a203c78c 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -157,6 +157,7 @@ #define OP_PAGE_PROGRAM_WITH_ECC 0x7 #define OP_PROGRAM_PAGE_SPARE 0x9 #define OP_BLOCK_ERASE 0xa +#define OP_CHECK_STATUS 0xc #define OP_FETCH_ID 0xb #define OP_RESET_DEVICE 0xd @@ -235,6 +236,8 @@ nandc_set_reg(chip, reg, \ */ #define NAND_ERASED_CW_SET BIT(4) +#define MAX_ADDRESS_CYCLE 5 + /* * This data type corresponds to the BAM transaction which will be used for all * NAND transfers. @@ -382,6 +385,9 @@ struct nandc_regs { * @reg_read_pos: marker for data read in reg_read_buf * * @cmd1/vld: some fixed controller register values + * + * @exec_opwrite: flag to select correct number of code word + * while reading status */ struct qcom_nand_controller { struct device *dev; @@ -432,6 +438,7 @@ struct qcom_nand_controller { int reg_read_pos; u32 cmd1, vld; + bool exec_opwrite; }; /* @@ -447,6 +454,29 @@ struct qcom_nand_boot_partition { u32 page_size; }; +/* + * Qcom op for each exec_op transfer + * + * @data_instr: data instruction pointer + * @data_instr_idx: data instruction index + * @rdy_timeout_ms: wait ready timeout in ms + * @rdy_delay_ns: Additional delay in ns + * @addr1_reg: Address1 register value + * @addr2_reg: Address2 register value + * @cmd_reg: CMD register value + * @flag: flag for misc instruction + */ +struct qcom_op { + const struct nand_op_instr *data_instr; + unsigned int data_instr_idx; + unsigned int rdy_timeout_ms; + unsigned int rdy_delay_ns; + u32 addr1_reg; + u32 addr2_reg; + u32 cmd_reg; + u8 flag; +}; + /* * NAND chip structure * @@ -1516,9 +1546,7 @@ static void pre_command(struct qcom_nand_host *host, int command) clear_read_regs(nandc); - if (command == NAND_CMD_RESET || command == NAND_CMD_READID || - command == NAND_CMD_PARAM || command == NAND_CMD_ERASE1) - clear_bam_transaction(nandc); + clear_bam_transaction(nandc); } /* @@ -2154,12 +2182,20 @@ static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf, { struct qcom_nand_host *host = to_qcom_nand_host(chip); struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + struct nand_ecc_ctrl *ecc = &chip->ecc; u8 *data_buf, *oob_buf = NULL; if (host->nr_boot_partitions) qcom_nandc_codeword_fixup(host, page); nand_read_page_op(chip, page, 0, NULL, 0); + nandc->buf_count = 0; + nandc->buf_start = 0; + host->use_ecc = true; + clear_read_regs(nandc); + set_address(host, 0, page); + update_rw_regs(host, ecc->steps, true, 0); + data_buf = buf; oob_buf = oob_required ? chip->oob_poi : NULL; @@ -2229,6 +2265,9 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const uint8_t *buf, nand_prog_page_begin_op(chip, page, 0, NULL, 0); + set_address(host, 0, page); + nandc->buf_count = 0; + nandc->buf_start = 0; clear_read_regs(nandc); clear_bam_transaction(nandc); @@ -2867,8 +2906,497 @@ static int qcom_nand_attach_chip(struct nand_chip *chip) return 0; } +static int qcom_op_cmd_mapping(struct qcom_nand_controller *nandc, u8 cmd, + struct qcom_op *q_op) +{ + int ret; + + switch (cmd) { + case NAND_CMD_RESET: + ret = OP_RESET_DEVICE; + break; + case NAND_CMD_READID: + ret = OP_FETCH_ID; + break; + case NAND_CMD_PARAM: + if (nandc->props->qpic_v2) + ret = OP_PAGE_READ_ONFI_READ; + else + ret = OP_PAGE_READ; + break; + case NAND_CMD_ERASE1: + case NAND_CMD_ERASE2: + ret = OP_BLOCK_ERASE; + break; + case NAND_CMD_STATUS: + ret = OP_CHECK_STATUS; + break; + case NAND_CMD_PAGEPROG: + ret = OP_PROGRAM_PAGE; + q_op->flag = OP_PROGRAM_PAGE; + nandc->exec_opwrite = true; + break; + } + + return ret; +} + +/* NAND framework ->exec_op() hooks and related helpers */ +static void qcom_parse_instructions(struct nand_chip *chip, + const struct nand_subop *subop, + struct qcom_op *q_op) +{ + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + const struct nand_op_instr *instr = NULL; + unsigned int op_id; + int i; + + memset(q_op, 0, sizeof(*q_op)); + + for (op_id = 0; op_id < subop->ninstrs; op_id++) { + unsigned int offset, naddrs; + const u8 *addrs; + + instr = &subop->instrs[op_id]; + + switch (instr->type) { + case NAND_OP_CMD_INSTR: + q_op->cmd_reg = qcom_op_cmd_mapping(nandc, instr->ctx.cmd.opcode, q_op); + q_op->rdy_delay_ns = instr->delay_ns; + break; + + case NAND_OP_ADDR_INSTR: + offset = nand_subop_get_addr_start_off(subop, op_id); + naddrs = nand_subop_get_num_addr_cyc(subop, op_id); + addrs = &instr->ctx.addr.addrs[offset]; + for (i = 0; i < MAX_ADDRESS_CYCLE; i++) { + if (i < 4) + q_op->addr1_reg |= (u32)addrs[i] << i * 8; + else + q_op->addr2_reg |= addrs[i]; + } + q_op->rdy_delay_ns = instr->delay_ns; + break; + + case NAND_OP_DATA_IN_INSTR: + q_op->data_instr = instr; + q_op->data_instr_idx = op_id; + q_op->rdy_delay_ns = instr->delay_ns; + fallthrough; + case NAND_OP_DATA_OUT_INSTR: + q_op->rdy_delay_ns = instr->delay_ns; + break; + + case NAND_OP_WAITRDY_INSTR: + q_op->rdy_timeout_ms = instr->ctx.waitrdy.timeout_ms; + q_op->rdy_delay_ns = instr->delay_ns; + break; + } + } +} + +static void qcom_delay_ns(unsigned int ns) +{ + if (!ns) + return; + + if (ns < 10000) + ndelay(ns); + else + udelay(DIV_ROUND_UP(ns, 1000)); +} + +static int qcom_wait_rdy_poll(struct nand_chip *chip, unsigned int time_ms) +{ + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + unsigned long start = jiffies + msecs_to_jiffies(time_ms); + u32 flash; + + nandc_read_buffer_sync(nandc, true); + + do { + flash = le32_to_cpu(nandc->reg_read_buf[0]); + if (flash & FS_READY_BSY_N) + return 0; + cpu_relax(); + } while (time_after(start, jiffies)); + + dev_err(nandc->dev, "Timeout waiting for device to be ready:0x%08x\n", flash); + + return -ETIMEDOUT; +} + +static int qcom_read_status_exec(struct nand_chip *chip, + const struct nand_subop *subop) +{ + struct qcom_nand_host *host = to_qcom_nand_host(chip); + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + struct nand_ecc_ctrl *ecc = &chip->ecc; + struct qcom_op q_op; + const struct nand_op_instr *instr = NULL; + unsigned int op_id = 0; + unsigned int len = 0; + int ret = 0, num_cw, i; + u32 flash_status; + + host->status = NAND_STATUS_READY | NAND_STATUS_WP; + + qcom_parse_instructions(chip, subop, &q_op); + + num_cw = nandc->exec_opwrite ? ecc->steps : 1; + nandc->exec_opwrite = false; + + nandc->buf_count = 0; + nandc->buf_start = 0; + host->use_ecc = false; + + clear_read_regs(nandc); + clear_bam_transaction(nandc); + + nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg); + nandc_set_reg(chip, NAND_EXEC_CMD, 1); + + write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); + + ret = submit_descs(nandc); + if (ret) { + dev_err(nandc->dev, "failure in submitting status descriptor\n"); + free_descs(nandc); + goto err_out; + } + free_descs(nandc); + + nandc_read_buffer_sync(nandc, true); + + for (i = 0; i < num_cw; i++) { + flash_status = le32_to_cpu(nandc->reg_read_buf[i]); + + if (flash_status & FS_MPU_ERR) + host->status &= ~NAND_STATUS_WP; + + if (flash_status & FS_OP_ERR || + (i == (num_cw - 1) && (flash_status & FS_DEVICE_STS_ERR))) + host->status |= NAND_STATUS_FAIL; + } + + flash_status = host->status; + instr = q_op.data_instr; + op_id = q_op.data_instr_idx; + len = nand_subop_get_data_len(subop, op_id); + memcpy(instr->ctx.data.buf.in, &flash_status, len); + +err_out: + return ret; +} + +static int qcom_read_id_type_exec(struct nand_chip *chip, const struct nand_subop *subop) +{ + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + struct qcom_nand_host *host = to_qcom_nand_host(chip); + struct qcom_op q_op; + const struct nand_op_instr *instr = NULL; + unsigned int op_id = 0; + unsigned int len = 0; + int ret = 0; + + qcom_parse_instructions(chip, subop, &q_op); + + nandc->buf_count = 0; + nandc->buf_start = 0; + host->use_ecc = false; + + clear_read_regs(nandc); + clear_bam_transaction(nandc); + + nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg); + nandc_set_reg(chip, NAND_ADDR0, q_op.addr1_reg); + nandc_set_reg(chip, NAND_ADDR1, q_op.addr2_reg); + nandc_set_reg(chip, NAND_FLASH_CHIP_SELECT, + nandc->props->is_bam ? 0 : DM_EN); + + nandc_set_reg(chip, NAND_EXEC_CMD, 1); + + write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + + read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL); + + ret = submit_descs(nandc); + if (ret) { + dev_err(nandc->dev, "failure in submitting read id descriptor\n"); + free_descs(nandc); + goto err_out; + } + free_descs(nandc); + + instr = q_op.data_instr; + op_id = q_op.data_instr_idx; + len = nand_subop_get_data_len(subop, op_id); + + nandc_read_buffer_sync(nandc, true); + memcpy(instr->ctx.data.buf.in, nandc->reg_read_buf, len); + +err_out: + return ret; +} + +static int qcom_misc_cmd_type_exec(struct nand_chip *chip, const struct nand_subop *subop) +{ + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + struct qcom_nand_host *host = to_qcom_nand_host(chip); + struct qcom_op q_op; + int ret = 0; + + qcom_parse_instructions(chip, subop, &q_op); + + if (q_op.flag == OP_PROGRAM_PAGE) + goto wait_rdy; + + nandc->buf_count = 0; + nandc->buf_start = 0; + host->use_ecc = false; + + clear_read_regs(nandc); + clear_bam_transaction(nandc); + + nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg); + nandc_set_reg(chip, NAND_EXEC_CMD, 1); + + write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + + read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); + + ret = submit_descs(nandc); + if (ret) { + dev_err(nandc->dev, "failure in submitting misc descriptor\n"); + free_descs(nandc); + goto err_out; + } + free_descs(nandc); + +wait_rdy: + qcom_delay_ns(q_op.rdy_delay_ns); + ret = qcom_wait_rdy_poll(chip, q_op.rdy_timeout_ms); + +err_out: + return ret; +} + +static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_subop *subop) +{ + struct qcom_nand_host *host = to_qcom_nand_host(chip); + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + struct qcom_op q_op; + const struct nand_op_instr *instr = NULL; + unsigned int op_id = 0; + unsigned int len = 0; + int ret = 0; + + qcom_parse_instructions(chip, subop, &q_op); + + q_op.cmd_reg |= PAGE_ACC | LAST_PAGE; + + nandc->buf_count = 0; + nandc->buf_start = 0; + host->use_ecc = false; + clear_read_regs(nandc); + clear_bam_transaction(nandc); + + nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg); + + nandc_set_reg(chip, NAND_ADDR0, 0); + nandc_set_reg(chip, NAND_ADDR1, 0); + nandc_set_reg(chip, NAND_DEV0_CFG0, 0 << CW_PER_PAGE + | 512 << UD_SIZE_BYTES + | 5 << NUM_ADDR_CYCLES + | 0 << SPARE_SIZE_BYTES); + nandc_set_reg(chip, NAND_DEV0_CFG1, 7 << NAND_RECOVERY_CYCLES + | 0 << CS_ACTIVE_BSY + | 17 << BAD_BLOCK_BYTE_NUM + | 1 << BAD_BLOCK_IN_SPARE_AREA + | 2 << WR_RD_BSY_GAP + | 0 << WIDE_FLASH + | 1 << DEV0_CFG1_ECC_DISABLE); + if (!nandc->props->qpic_v2) + nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE); + + /* configure CMD1 and VLD for ONFI param probing in QPIC v1 */ + if (!nandc->props->qpic_v2) { + nandc_set_reg(chip, NAND_DEV_CMD_VLD, + (nandc->vld & ~READ_START_VLD)); + nandc_set_reg(chip, NAND_DEV_CMD1, + (nandc->cmd1 & ~(0xFF << READ_ADDR)) + | NAND_CMD_PARAM << READ_ADDR); + } + + nandc_set_reg(chip, NAND_EXEC_CMD, 1); + + if (!nandc->props->qpic_v2) { + nandc_set_reg(chip, NAND_DEV_CMD1_RESTORE, nandc->cmd1); + nandc_set_reg(chip, NAND_DEV_CMD_VLD_RESTORE, nandc->vld); + } + + instr = q_op.data_instr; + op_id = q_op.data_instr_idx; + len = nand_subop_get_data_len(subop, op_id); + + nandc_set_read_loc(chip, 0, 0, 0, len, 1); + + if (!nandc->props->qpic_v2) { + write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0); + write_reg_dma(nandc, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL); + } + + nandc->buf_count = len; + memset(nandc->data_buffer, 0xff, nandc->buf_count); + + config_nand_single_cw_page_read(chip, false, 0); + + read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, + nandc->buf_count, 0); + + /* restore CMD1 and VLD regs */ + if (!nandc->props->qpic_v2) { + write_reg_dma(nandc, NAND_DEV_CMD1_RESTORE, 1, 0); + write_reg_dma(nandc, NAND_DEV_CMD_VLD_RESTORE, 1, NAND_BAM_NEXT_SGL); + } + + ret = submit_descs(nandc); + if (ret) { + dev_err(nandc->dev, "failure in submitting param page descriptor\n"); + free_descs(nandc); + goto err_out; + } + free_descs(nandc); + + ret = qcom_wait_rdy_poll(chip, q_op.rdy_timeout_ms); + if (ret) + goto err_out; + + memcpy(instr->ctx.data.buf.in, nandc->data_buffer, len); + +err_out: + return ret; +} + +static int qcom_erase_cmd_type_exec(struct nand_chip *chip, const struct nand_subop *subop) +{ + struct qcom_nand_host *host = to_qcom_nand_host(chip); + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + struct qcom_op q_op; + int ret = 0; + + qcom_parse_instructions(chip, subop, &q_op); + + q_op.cmd_reg |= PAGE_ACC | LAST_PAGE; + + nandc->buf_count = 0; + nandc->buf_start = 0; + host->use_ecc = false; + clear_read_regs(nandc); + clear_bam_transaction(nandc); + + nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg); + nandc_set_reg(chip, NAND_ADDR0, q_op.addr1_reg); + nandc_set_reg(chip, NAND_ADDR1, q_op.addr2_reg); + nandc_set_reg(chip, NAND_DEV0_CFG0, + host->cfg0_raw & ~(7 << CW_PER_PAGE)); + nandc_set_reg(chip, NAND_DEV0_CFG1, host->cfg1_raw); + nandc_set_reg(chip, NAND_EXEC_CMD, 1); + + write_reg_dma(nandc, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + + ret = submit_descs(nandc); + if (ret) { + dev_err(nandc->dev, "failure in submitting erase descriptor\n"); + free_descs(nandc); + goto err_out; + } + free_descs(nandc); + + ret = qcom_wait_rdy_poll(chip, q_op.rdy_timeout_ms); + if (ret) + goto err_out; + +err_out: + return ret; +} + +static const struct nand_op_parser qcom_op_parser = NAND_OP_PARSER( + NAND_OP_PARSER_PATTERN( + qcom_misc_cmd_type_exec, + NAND_OP_PARSER_PAT_CMD_ELEM(false), + NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)), + NAND_OP_PARSER_PATTERN( + qcom_read_id_type_exec, + NAND_OP_PARSER_PAT_CMD_ELEM(false), + NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDRESS_CYCLE), + NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 8)), + NAND_OP_PARSER_PATTERN( + qcom_read_status_exec, + NAND_OP_PARSER_PAT_CMD_ELEM(false), + NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 1)), + NAND_OP_PARSER_PATTERN( + qcom_param_page_type_exec, + NAND_OP_PARSER_PAT_CMD_ELEM(false), + NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDRESS_CYCLE), + NAND_OP_PARSER_PAT_WAITRDY_ELEM(true), + NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 512)), + NAND_OP_PARSER_PATTERN( + qcom_erase_cmd_type_exec, + NAND_OP_PARSER_PAT_CMD_ELEM(false), + NAND_OP_PARSER_PAT_ADDR_ELEM(false, MAX_ADDRESS_CYCLE), + NAND_OP_PARSER_PAT_CMD_ELEM(false), + NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)), + ); + +static int qcom_check_op(struct nand_chip *chip, + const struct nand_operation *op) +{ + const struct nand_op_instr *instr; + int op_id; + + for (op_id = 0; op_id < op->ninstrs; op_id++) { + instr = &op->instrs[op_id]; + + switch (instr->type) { + case NAND_OP_CMD_INSTR: + if (instr->ctx.cmd.opcode != NAND_CMD_RESET || + instr->ctx.cmd.opcode != NAND_CMD_READID || + instr->ctx.cmd.opcode != NAND_CMD_PARAM || + instr->ctx.cmd.opcode != NAND_CMD_ERASE1 || + instr->ctx.cmd.opcode != NAND_CMD_ERASE2 || + instr->ctx.cmd.opcode != NAND_CMD_STATUS || + instr->ctx.cmd.opcode != NAND_CMD_PAGEPROG) + return -ENOTSUPP; + break; + default: + break; + } + } + + return 0; +} + +static int qcom_nand_exec_op(struct nand_chip *chip, + const struct nand_operation *op, + bool check_only) +{ + if (check_only) + return qcom_check_op(chip, op); + + return nand_op_parser_exec_op(chip, &qcom_op_parser, + op, check_only); +} + static const struct nand_controller_ops qcom_nandc_ops = { .attach_chip = qcom_nand_attach_chip, + .exec_op = qcom_nand_exec_op, }; static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc) -- GitLab From 2e7f735b38a502c47894c8d5f6bd71c6957d0b62 Mon Sep 17 00:00:00 2001 From: Md Sadre Alam Date: Mon, 10 Jul 2023 11:14:40 +0530 Subject: [PATCH 0209/3445] mtd: rawnand: qcom: Remove legacy interface Remove legacy interface implementation Co-developed-by: Sricharan Ramabadhran Signed-off-by: Sricharan Ramabadhran Signed-off-by: Md Sadre Alam Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230710054440.23297-2-quic_mdalam@quicinc.com --- drivers/mtd/nand/raw/qcom_nandc.c | 359 ------------------------------ 1 file changed, 359 deletions(-) diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 852c6a203c78c..b1e69d634d4a8 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -1303,155 +1303,6 @@ static void config_nand_cw_write(struct nand_chip *chip) write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL); } -/* - * the following functions are used within chip->legacy.cmdfunc() to - * perform different NAND_CMD_* commands - */ - -/* sets up descriptors for NAND_CMD_PARAM */ -static int nandc_param(struct qcom_nand_host *host) -{ - struct nand_chip *chip = &host->chip; - struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - - /* - * NAND_CMD_PARAM is called before we know much about the FLASH chip - * in use. we configure the controller to perform a raw read of 512 - * bytes to read onfi params - */ - if (nandc->props->qpic_v2) - nandc_set_reg(chip, NAND_FLASH_CMD, OP_PAGE_READ_ONFI_READ | - PAGE_ACC | LAST_PAGE); - else - nandc_set_reg(chip, NAND_FLASH_CMD, OP_PAGE_READ | - PAGE_ACC | LAST_PAGE); - - nandc_set_reg(chip, NAND_ADDR0, 0); - nandc_set_reg(chip, NAND_ADDR1, 0); - nandc_set_reg(chip, NAND_DEV0_CFG0, 0 << CW_PER_PAGE - | 512 << UD_SIZE_BYTES - | 5 << NUM_ADDR_CYCLES - | 0 << SPARE_SIZE_BYTES); - nandc_set_reg(chip, NAND_DEV0_CFG1, 7 << NAND_RECOVERY_CYCLES - | 0 << CS_ACTIVE_BSY - | 17 << BAD_BLOCK_BYTE_NUM - | 1 << BAD_BLOCK_IN_SPARE_AREA - | 2 << WR_RD_BSY_GAP - | 0 << WIDE_FLASH - | 1 << DEV0_CFG1_ECC_DISABLE); - if (!nandc->props->qpic_v2) - nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE); - - /* configure CMD1 and VLD for ONFI param probing in QPIC v1 */ - if (!nandc->props->qpic_v2) { - nandc_set_reg(chip, NAND_DEV_CMD_VLD, - (nandc->vld & ~READ_START_VLD)); - nandc_set_reg(chip, NAND_DEV_CMD1, - (nandc->cmd1 & ~(0xFF << READ_ADDR)) - | NAND_CMD_PARAM << READ_ADDR); - } - - nandc_set_reg(chip, NAND_EXEC_CMD, 1); - - if (!nandc->props->qpic_v2) { - nandc_set_reg(chip, NAND_DEV_CMD1_RESTORE, nandc->cmd1); - nandc_set_reg(chip, NAND_DEV_CMD_VLD_RESTORE, nandc->vld); - } - - nandc_set_read_loc(chip, 0, 0, 0, 512, 1); - - if (!nandc->props->qpic_v2) { - write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0); - write_reg_dma(nandc, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL); - } - - nandc->buf_count = 512; - memset(nandc->data_buffer, 0xff, nandc->buf_count); - - config_nand_single_cw_page_read(chip, false, 0); - - read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, - nandc->buf_count, 0); - - /* restore CMD1 and VLD regs */ - if (!nandc->props->qpic_v2) { - write_reg_dma(nandc, NAND_DEV_CMD1_RESTORE, 1, 0); - write_reg_dma(nandc, NAND_DEV_CMD_VLD_RESTORE, 1, NAND_BAM_NEXT_SGL); - } - - return 0; -} - -/* sets up descriptors for NAND_CMD_ERASE1 */ -static int erase_block(struct qcom_nand_host *host, int page_addr) -{ - struct nand_chip *chip = &host->chip; - struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - - nandc_set_reg(chip, NAND_FLASH_CMD, - OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE); - nandc_set_reg(chip, NAND_ADDR0, page_addr); - nandc_set_reg(chip, NAND_ADDR1, 0); - nandc_set_reg(chip, NAND_DEV0_CFG0, - host->cfg0_raw & ~(7 << CW_PER_PAGE)); - nandc_set_reg(chip, NAND_DEV0_CFG1, host->cfg1_raw); - nandc_set_reg(chip, NAND_EXEC_CMD, 1); - nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus); - nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus); - - write_reg_dma(nandc, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); - - read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); - - write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0); - write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL); - - return 0; -} - -/* sets up descriptors for NAND_CMD_READID */ -static int read_id(struct qcom_nand_host *host, int column) -{ - struct nand_chip *chip = &host->chip; - struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - - if (column == -1) - return 0; - - nandc_set_reg(chip, NAND_FLASH_CMD, OP_FETCH_ID); - nandc_set_reg(chip, NAND_ADDR0, column); - nandc_set_reg(chip, NAND_ADDR1, 0); - nandc_set_reg(chip, NAND_FLASH_CHIP_SELECT, - nandc->props->is_bam ? 0 : DM_EN); - nandc_set_reg(chip, NAND_EXEC_CMD, 1); - - write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); - - read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL); - - return 0; -} - -/* sets up descriptors for NAND_CMD_RESET */ -static int reset(struct qcom_nand_host *host) -{ - struct nand_chip *chip = &host->chip; - struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - - nandc_set_reg(chip, NAND_FLASH_CMD, OP_RESET_DEVICE); - nandc_set_reg(chip, NAND_EXEC_CMD, 1); - - write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); - - read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); - - return 0; -} - /* helpers to submit/free our list of dma descriptors */ static int submit_descs(struct qcom_nand_controller *nandc) { @@ -1534,150 +1385,6 @@ static void clear_read_regs(struct qcom_nand_controller *nandc) nandc_read_buffer_sync(nandc, false); } -static void pre_command(struct qcom_nand_host *host, int command) -{ - struct nand_chip *chip = &host->chip; - struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - - nandc->buf_count = 0; - nandc->buf_start = 0; - host->use_ecc = false; - host->last_command = command; - - clear_read_regs(nandc); - - clear_bam_transaction(nandc); -} - -/* - * this is called after NAND_CMD_PAGEPROG and NAND_CMD_ERASE1 to set our - * privately maintained status byte, this status byte can be read after - * NAND_CMD_STATUS is called - */ -static void parse_erase_write_errors(struct qcom_nand_host *host, int command) -{ - struct nand_chip *chip = &host->chip; - struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - struct nand_ecc_ctrl *ecc = &chip->ecc; - int num_cw; - int i; - - num_cw = command == NAND_CMD_PAGEPROG ? ecc->steps : 1; - nandc_read_buffer_sync(nandc, true); - - for (i = 0; i < num_cw; i++) { - u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]); - - if (flash_status & FS_MPU_ERR) - host->status &= ~NAND_STATUS_WP; - - if (flash_status & FS_OP_ERR || (i == (num_cw - 1) && - (flash_status & - FS_DEVICE_STS_ERR))) - host->status |= NAND_STATUS_FAIL; - } -} - -static void post_command(struct qcom_nand_host *host, int command) -{ - struct nand_chip *chip = &host->chip; - struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - - switch (command) { - case NAND_CMD_READID: - nandc_read_buffer_sync(nandc, true); - memcpy(nandc->data_buffer, nandc->reg_read_buf, - nandc->buf_count); - break; - case NAND_CMD_PAGEPROG: - case NAND_CMD_ERASE1: - parse_erase_write_errors(host, command); - break; - default: - break; - } -} - -/* - * Implements chip->legacy.cmdfunc. It's only used for a limited set of - * commands. The rest of the commands wouldn't be called by upper layers. - * For example, NAND_CMD_READOOB would never be called because we have our own - * versions of read_oob ops for nand_ecc_ctrl. - */ -static void qcom_nandc_command(struct nand_chip *chip, unsigned int command, - int column, int page_addr) -{ - struct qcom_nand_host *host = to_qcom_nand_host(chip); - struct nand_ecc_ctrl *ecc = &chip->ecc; - struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - bool wait = false; - int ret = 0; - - pre_command(host, command); - - switch (command) { - case NAND_CMD_RESET: - ret = reset(host); - wait = true; - break; - - case NAND_CMD_READID: - nandc->buf_count = 4; - ret = read_id(host, column); - wait = true; - break; - - case NAND_CMD_PARAM: - ret = nandc_param(host); - wait = true; - break; - - case NAND_CMD_ERASE1: - ret = erase_block(host, page_addr); - wait = true; - break; - - case NAND_CMD_READ0: - /* we read the entire page for now */ - WARN_ON(column != 0); - - host->use_ecc = true; - set_address(host, 0, page_addr); - update_rw_regs(host, ecc->steps, true, 0); - break; - - case NAND_CMD_SEQIN: - WARN_ON(column != 0); - set_address(host, 0, page_addr); - break; - - case NAND_CMD_PAGEPROG: - case NAND_CMD_STATUS: - case NAND_CMD_NONE: - default: - break; - } - - if (ret) { - dev_err(nandc->dev, "failure executing command %d\n", - command); - free_descs(nandc); - return; - } - - if (wait) { - ret = submit_descs(nandc); - if (ret) - dev_err(nandc->dev, - "failure submitting descs for command %d\n", - command); - } - - free_descs(nandc); - - post_command(host, command); -} - /* * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS. @@ -2533,64 +2240,6 @@ static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs) return nand_prog_page_end_op(chip); } -/* - * the three functions below implement chip->legacy.read_byte(), - * chip->legacy.read_buf() and chip->legacy.write_buf() respectively. these - * aren't used for reading/writing page data, they are used for smaller data - * like reading id, status etc - */ -static uint8_t qcom_nandc_read_byte(struct nand_chip *chip) -{ - struct qcom_nand_host *host = to_qcom_nand_host(chip); - struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - u8 *buf = nandc->data_buffer; - u8 ret = 0x0; - - if (host->last_command == NAND_CMD_STATUS) { - ret = host->status; - - host->status = NAND_STATUS_READY | NAND_STATUS_WP; - - return ret; - } - - if (nandc->buf_start < nandc->buf_count) - ret = buf[nandc->buf_start++]; - - return ret; -} - -static void qcom_nandc_read_buf(struct nand_chip *chip, uint8_t *buf, int len) -{ - struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start); - - memcpy(buf, nandc->data_buffer + nandc->buf_start, real_len); - nandc->buf_start += real_len; -} - -static void qcom_nandc_write_buf(struct nand_chip *chip, const uint8_t *buf, - int len) -{ - struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start); - - memcpy(nandc->data_buffer + nandc->buf_start, buf, real_len); - - nandc->buf_start += real_len; -} - -/* we support only one external chip for now */ -static void qcom_nandc_select_chip(struct nand_chip *chip, int chipnr) -{ - struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - - if (chipnr <= 0) - return; - - dev_warn(nandc->dev, "invalid chip select\n"); -} - /* * NAND controller page layout info * @@ -3663,14 +3312,6 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc, mtd->owner = THIS_MODULE; mtd->dev.parent = dev; - chip->legacy.cmdfunc = qcom_nandc_command; - chip->legacy.select_chip = qcom_nandc_select_chip; - chip->legacy.read_byte = qcom_nandc_read_byte; - chip->legacy.read_buf = qcom_nandc_read_buf; - chip->legacy.write_buf = qcom_nandc_write_buf; - chip->legacy.set_features = nand_get_set_features_notsupp; - chip->legacy.get_features = nand_get_set_features_notsupp; - /* * the bad block marker is readable only when we read the last codeword * of a page with ECC disabled. currently, the nand_base and nand_bbt -- GitLab From bd60fcf27654d2acbb1f0d115daefaac6118b74c Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Mon, 3 Jul 2023 15:50:42 +1200 Subject: [PATCH 0210/3445] dt-bindings: mtd: Add AC5 specific binding Add binding for AC5 SoC. This SoC only supports NAND SDR timings up to mode 3 so a specific compatible value is needed. Signed-off-by: Chris Packham Acked-by: Conor Dooley Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230703035044.2063303-2-chris.packham@alliedtelesis.co.nz --- .../devicetree/bindings/mtd/marvell,nand-controller.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mtd/marvell,nand-controller.yaml b/Documentation/devicetree/bindings/mtd/marvell,nand-controller.yaml index a10729bb18400..1ecea848e8b90 100644 --- a/Documentation/devicetree/bindings/mtd/marvell,nand-controller.yaml +++ b/Documentation/devicetree/bindings/mtd/marvell,nand-controller.yaml @@ -16,6 +16,7 @@ properties: - const: marvell,armada-8k-nand-controller - const: marvell,armada370-nand-controller - enum: + - marvell,ac5-nand-controller - marvell,armada370-nand-controller - marvell,pxa3xx-nand-controller - description: legacy bindings -- GitLab From 72b9a3fc4b601ab64181a036c3a78948f46b8608 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Mon, 3 Jul 2023 15:50:44 +1200 Subject: [PATCH 0211/3445] mtd: rawnand: marvell: add support for AC5 SoC Add support for the AC5/AC5X SoC from Marvell. The NFC on this SoC only supports SDR modes up to 3. Marvell's SDK includes some predefined values for the ndtr registers. These haven't been incorporated as the existing code seems to get good values based on measurements taken with an oscilloscope. Signed-off-by: Chris Packham Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230703035044.2063303-4-chris.packham@alliedtelesis.co.nz --- drivers/mtd/nand/raw/Kconfig | 2 +- drivers/mtd/nand/raw/marvell_nand.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 5b871e2f5c5e4..cbf8ae85e1ae0 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -160,7 +160,7 @@ config MTD_NAND_MARVELL including: - PXA3xx processors (NFCv1) - 32-bit Armada platforms (XP, 37x, 38x, 39x) (NFCv2) - - 64-bit Aramda platforms (7k, 8k) (NFCv2) + - 64-bit Aramda platforms (7k, 8k, ac5) (NFCv2) config MTD_NAND_SLC_LPC32XX tristate "NXP LPC32xx SLC NAND controller" diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c index 30c15e4e1cc0d..b9a8dd3242110 100644 --- a/drivers/mtd/nand/raw/marvell_nand.c +++ b/drivers/mtd/nand/raw/marvell_nand.c @@ -375,6 +375,7 @@ static inline struct marvell_nand_chip_sel *to_nand_sel(struct marvell_nand_chip * BCH error detection and correction algorithm, * NDCB3 register has been added * @use_dma: Use dma for data transfers + * @max_mode_number: Maximum timing mode supported by the controller */ struct marvell_nfc_caps { unsigned int max_cs_nb; @@ -383,6 +384,7 @@ struct marvell_nfc_caps { bool legacy_of_bindings; bool is_nfcv2; bool use_dma; + unsigned int max_mode_number; }; /** @@ -2376,6 +2378,9 @@ static int marvell_nfc_setup_interface(struct nand_chip *chip, int chipnr, if (IS_ERR(sdr)) return PTR_ERR(sdr); + if (nfc->caps->max_mode_number && nfc->caps->max_mode_number < conf->timings.mode) + return -EOPNOTSUPP; + /* * SDR timings are given in pico-seconds while NFC timings must be * expressed in NAND controller clock cycles, which is half of the @@ -3073,6 +3078,13 @@ static const struct marvell_nfc_caps marvell_armada_8k_nfc_caps = { .is_nfcv2 = true, }; +static const struct marvell_nfc_caps marvell_ac5_caps = { + .max_cs_nb = 2, + .max_rb_nb = 1, + .is_nfcv2 = true, + .max_mode_number = 3, +}; + static const struct marvell_nfc_caps marvell_armada370_nfc_caps = { .max_cs_nb = 4, .max_rb_nb = 2, @@ -3121,6 +3133,10 @@ static const struct of_device_id marvell_nfc_of_ids[] = { .compatible = "marvell,armada-8k-nand-controller", .data = &marvell_armada_8k_nfc_caps, }, + { + .compatible = "marvell,ac5-nand-controller", + .data = &marvell_ac5_caps, + }, { .compatible = "marvell,armada370-nand-controller", .data = &marvell_armada370_nfc_caps, -- GitLab From e0b3187f6e39a8447aa839237391221dc99169ae Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 12 Jul 2023 17:10:42 +0200 Subject: [PATCH 0212/3445] dt-bindings: mtd: Fix nand-controller.yaml license Binding files should be dual licensed. This file was initially written as a .txt file with no specific license, so was implicitely GPLv2. Significant part of this file and its conversion into yaml were written by Bootlin employees which agree to comply with the rules regarding the dual licensing so let's fix the SPDX tag to reflect the correct license by changing it from GPL to GPL + BSD-2-Clause. Signed-off-by: Miquel Raynal Acked-by: Maxime Ripard Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/linux-mtd/20230712151042.433593-1-miquel.raynal@bootlin.com --- Documentation/devicetree/bindings/mtd/nand-controller.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mtd/nand-controller.yaml b/Documentation/devicetree/bindings/mtd/nand-controller.yaml index 83a4fe4cc29d3..28167c0cf2719 100644 --- a/Documentation/devicetree/bindings/mtd/nand-controller.yaml +++ b/Documentation/devicetree/bindings/mtd/nand-controller.yaml @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0 +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- $id: http://devicetree.org/schemas/mtd/nand-controller.yaml# -- GitLab From c3519aed2a3faf77b66350214fb5caa9a0905888 Mon Sep 17 00:00:00 2001 From: Arseniy Krasnov Date: Tue, 11 Jul 2023 15:21:27 +0300 Subject: [PATCH 0213/3445] dt-bindings: nand: meson: support for 512B ECC step size Meson NAND supports both 512B and 1024B ECC step size, so replace 'const' for only 1024B step size with enum for both sizes. Signed-off-by: Arseniy Krasnov Acked-by: Rob Herring Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230711122129.2635558-2-AVKrasnov@sberdevices.ru --- Documentation/devicetree/bindings/mtd/amlogic,meson-nand.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mtd/amlogic,meson-nand.yaml b/Documentation/devicetree/bindings/mtd/amlogic,meson-nand.yaml index 787ef488dd5b1..a98b5d61ea5d5 100644 --- a/Documentation/devicetree/bindings/mtd/amlogic,meson-nand.yaml +++ b/Documentation/devicetree/bindings/mtd/amlogic,meson-nand.yaml @@ -50,7 +50,7 @@ patternProperties: const: hw nand-ecc-step-size: - const: 1024 + enum: [512, 1024] nand-ecc-strength: enum: [8, 16, 24, 30, 40, 50, 60] -- GitLab From de2a5d52f2c052814349013e8a77d1bc02717d74 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 13 Jul 2023 00:16:41 +0200 Subject: [PATCH 0214/3445] dt-bindings: mtd: Add SEAMA partition bindings This types of NAND partitions appear in OpenWrt and U-Boot. Signed-off-by: Linus Walleij Reviewed-by: Rob Herring Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230713-seama-partitions-v4-1-69e577453d40@linaro.org --- .../bindings/mtd/partitions/seama.yaml | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 Documentation/devicetree/bindings/mtd/partitions/seama.yaml diff --git a/Documentation/devicetree/bindings/mtd/partitions/seama.yaml b/Documentation/devicetree/bindings/mtd/partitions/seama.yaml new file mode 100644 index 0000000000000..4c1cbf43e81a6 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/partitions/seama.yaml @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mtd/partitions/seama.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Seattle Image Partitions + +description: The SEAttle iMAge (SEAMA) partition is a type of partition + used for NAND flash devices. This type of flash image is found in some + D-Link routers such as DIR-645, DIR-842, DIR-859, DIR-860L, DIR-885L, + DIR890L and DCH-M225, as well as in WD and NEC routers on the ath79 + (MIPS), Broadcom BCM53xx, and RAMIPS platforms. This partition type + does not have children defined in the device tree, they need to be + detected by software. + +allOf: + - $ref: partition.yaml# + +maintainers: + - Linus Walleij + +properties: + compatible: + const: seama + +required: + - compatible + +unevaluatedProperties: false + +examples: + - | + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + compatible = "seama"; + reg = <0x0 0x800000>; + label = "firmware"; + }; + }; -- GitLab From 3440d8da79ba983330457b2400b15e7b1b002ac3 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Jul 2023 11:49:33 -0600 Subject: [PATCH 0215/3445] remoteproc: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230714174935.4063513-1-robh@kernel.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/imx_dsp_rproc.c | 3 +-- drivers/remoteproc/imx_rproc.c | 2 +- drivers/remoteproc/omap_remoteproc.c | 3 ++- drivers/remoteproc/pru_rproc.c | 3 ++- drivers/remoteproc/qcom_q6v5_adsp.c | 2 +- drivers/remoteproc/qcom_q6v5_mss.c | 3 ++- drivers/remoteproc/qcom_q6v5_pas.c | 2 +- drivers/remoteproc/qcom_sysmon.c | 1 - drivers/remoteproc/qcom_wcnss.c | 2 +- drivers/remoteproc/qcom_wcnss_iris.c | 1 + drivers/remoteproc/rcar_rproc.c | 3 ++- drivers/remoteproc/st_slim_rproc.c | 1 - drivers/remoteproc/stm32_rproc.c | 4 ++-- drivers/remoteproc/ti_k3_dsp_remoteproc.c | 2 +- drivers/remoteproc/ti_k3_r5_remoteproc.c | 3 ++- drivers/remoteproc/wkup_m3_rproc.c | 2 +- 16 files changed, 20 insertions(+), 17 deletions(-) diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c index d95fa55861899..8fcda9b745459 100644 --- a/drivers/remoteproc/imx_dsp_rproc.c +++ b/drivers/remoteproc/imx_dsp_rproc.c @@ -12,8 +12,7 @@ #include #include #include -#include -#include +#include #include #include #include diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index f9874fc5a80ff..b403a37ddb02e 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -13,9 +13,9 @@ #include #include #include +#include #include #include -#include #include #include #include diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c index 82ed90f03d91b..8f50ab80e56f4 100644 --- a/drivers/remoteproc/omap_remoteproc.c +++ b/drivers/remoteproc/omap_remoteproc.c @@ -19,7 +19,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c index 2874c8d324f79..5b2dc75836fc6 100644 --- a/drivers/remoteproc/pru_rproc.c +++ b/drivers/remoteproc/pru_rproc.c @@ -16,8 +16,9 @@ #include #include #include -#include +#include #include +#include #include #include #include diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c index 6777a3bd62264..7733be477db58 100644 --- a/drivers/remoteproc/qcom_q6v5_adsp.c +++ b/drivers/remoteproc/qcom_q6v5_adsp.c @@ -14,8 +14,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 70bffc9f33f6c..76c546871a949 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -15,9 +15,10 @@ #include #include #include +#include #include -#include #include +#include #include #include #include diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 3153d82037e71..faec3a3d8e4ef 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -13,8 +13,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/drivers/remoteproc/qcom_sysmon.c b/drivers/remoteproc/qcom_sysmon.c index 746f56b4bafbe..c24e4a8828738 100644 --- a/drivers/remoteproc/qcom_sysmon.c +++ b/drivers/remoteproc/qcom_sysmon.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index 1ed0647bc962d..c109096bbfe33 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -14,8 +14,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/drivers/remoteproc/qcom_wcnss_iris.c b/drivers/remoteproc/qcom_wcnss_iris.c index 09720ddddc857..dd36fd077911a 100644 --- a/drivers/remoteproc/qcom_wcnss_iris.c +++ b/drivers/remoteproc/qcom_wcnss_iris.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/remoteproc/rcar_rproc.c b/drivers/remoteproc/rcar_rproc.c index 90e8769d56248..cc17e8421f65b 100644 --- a/drivers/remoteproc/rcar_rproc.c +++ b/drivers/remoteproc/rcar_rproc.c @@ -5,8 +5,9 @@ #include #include -#include +#include #include +#include #include #include #include diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c index 4ed9467897e5b..d17719384c165 100644 --- a/drivers/remoteproc/st_slim_rproc.c +++ b/drivers/remoteproc/st_slim_rproc.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c index cf073bac79f73..98234b44f0389 100644 --- a/drivers/remoteproc/stm32_rproc.c +++ b/drivers/remoteproc/stm32_rproc.c @@ -12,9 +12,9 @@ #include #include #include -#include -#include +#include #include +#include #include #include #include diff --git a/drivers/remoteproc/ti_k3_dsp_remoteproc.c b/drivers/remoteproc/ti_k3_dsp_remoteproc.c index ec626a37fef60..ef8415a7cd542 100644 --- a/drivers/remoteproc/ti_k3_dsp_remoteproc.c +++ b/drivers/remoteproc/ti_k3_dsp_remoteproc.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/remoteproc/ti_k3_r5_remoteproc.c b/drivers/remoteproc/ti_k3_r5_remoteproc.c index 23fe44d4d7a58..ad3415a3851b2 100644 --- a/drivers/remoteproc/ti_k3_r5_remoteproc.c +++ b/drivers/remoteproc/ti_k3_r5_remoteproc.c @@ -12,9 +12,10 @@ #include #include #include +#include #include -#include #include +#include #include #include #include diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c index 120dc7d2dac19..36a55f7ffa64d 100644 --- a/drivers/remoteproc/wkup_m3_rproc.c +++ b/drivers/remoteproc/wkup_m3_rproc.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include -- GitLab From 1e5c6933483b7cf8eab9e2b1c8a12af1451df4fa Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 13 Jul 2023 09:22:39 +0200 Subject: [PATCH 0216/3445] dt-bindings: remoteproc: qcom,pas: correct memory-region constraints Qualcomm PAS devices expect exactly one memory region, not many. Also, the memory-region is now defined in device specific binding, not in qcom,pas-common.yaml, thus also require it in the same place. Fixes: cee616c68846 ("dt-bindings: remoteproc: qcom: adsp: move memory-region and firmware-name out of pas-common") Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230713072242.11268-2-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml | 1 + .../devicetree/bindings/remoteproc/qcom,pas-common.yaml | 1 - .../devicetree/bindings/remoteproc/qcom,qcs404-pas.yaml | 3 ++- .../devicetree/bindings/remoteproc/qcom,sc7180-pas.yaml | 3 ++- .../devicetree/bindings/remoteproc/qcom,sc8180x-pas.yaml | 3 ++- .../devicetree/bindings/remoteproc/qcom,sc8280xp-pas.yaml | 3 ++- .../devicetree/bindings/remoteproc/qcom,sdx55-pas.yaml | 3 ++- .../devicetree/bindings/remoteproc/qcom,sm6350-pas.yaml | 3 ++- .../devicetree/bindings/remoteproc/qcom,sm8150-pas.yaml | 3 ++- .../devicetree/bindings/remoteproc/qcom,sm8350-pas.yaml | 3 ++- 10 files changed, 17 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml index 643ee787a81fc..b571efe6d5502 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml @@ -46,6 +46,7 @@ properties: required: - compatible + - memory-region unevaluatedProperties: false diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml index 171ef85de193e..63a82e7a8bf88 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,pas-common.yaml @@ -82,7 +82,6 @@ required: - clock-names - interrupts - interrupt-names - - memory-region - qcom,smem-states - qcom,smem-state-names diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,qcs404-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,qcs404-pas.yaml index 5efa0e5c04397..eb868a7ff4cd8 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,qcs404-pas.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,qcs404-pas.yaml @@ -42,7 +42,7 @@ properties: smd-edge: false memory-region: - minItems: 1 + maxItems: 1 description: Reference to the reserved-memory for the Hexagon core firmware-name: @@ -52,6 +52,7 @@ properties: required: - compatible - reg + - memory-region allOf: - $ref: /schemas/remoteproc/qcom,pas-common.yaml# diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-pas.yaml index 5cefd2c58593f..689d5d5353318 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-pas.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-pas.yaml @@ -51,7 +51,7 @@ properties: - const: mss memory-region: - minItems: 1 + maxItems: 1 description: Reference to the reserved-memory for the Hexagon core qcom,qmp: @@ -67,6 +67,7 @@ properties: required: - compatible - reg + - memory-region allOf: - $ref: /schemas/remoteproc/qcom,pas-common.yaml# diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sc8180x-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sc8180x-pas.yaml index c1f8dd8d0e4c1..4744a37b2b5d7 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,sc8180x-pas.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,sc8180x-pas.yaml @@ -38,7 +38,7 @@ properties: smd-edge: false memory-region: - minItems: 1 + maxItems: 1 description: Reference to the reserved-memory for the Hexagon core firmware-name: @@ -48,6 +48,7 @@ properties: required: - compatible - reg + - memory-region allOf: - $ref: /schemas/remoteproc/qcom,pas-common.yaml# diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sc8280xp-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sc8280xp-pas.yaml index f6fbc531dc280..96d53baf6e007 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,sc8280xp-pas.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,sc8280xp-pas.yaml @@ -38,7 +38,7 @@ properties: smd-edge: false memory-region: - minItems: 1 + maxItems: 1 description: Reference to the reserved-memory for the Hexagon core firmware-name: @@ -48,6 +48,7 @@ properties: required: - compatible - reg + - memory-region allOf: - $ref: /schemas/remoteproc/qcom,pas-common.yaml# diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sdx55-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sdx55-pas.yaml index c66e298462c73..5d463272165fd 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,sdx55-pas.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,sdx55-pas.yaml @@ -46,7 +46,7 @@ properties: - const: mss memory-region: - minItems: 1 + maxItems: 1 description: Reference to the reserved-memory for the Hexagon core qcom,qmp: @@ -62,6 +62,7 @@ properties: required: - compatible - reg + - memory-region allOf: - $ref: /schemas/remoteproc/qcom,pas-common.yaml# diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sm6350-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sm6350-pas.yaml index fee02fa800b5b..f7e40fb166da1 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,sm6350-pas.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,sm6350-pas.yaml @@ -36,7 +36,7 @@ properties: description: Reference to the AOSS side-channel message RAM. memory-region: - minItems: 1 + maxItems: 1 description: Reference to the reserved-memory for the Hexagon core smd-edge: false @@ -48,6 +48,7 @@ properties: required: - compatible - reg + - memory-region allOf: - $ref: /schemas/remoteproc/qcom,pas-common.yaml# diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sm8150-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sm8150-pas.yaml index 2c085ac2c3fb4..238c6e5e67c56 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,sm8150-pas.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,sm8150-pas.yaml @@ -40,7 +40,7 @@ properties: description: Reference to the AOSS side-channel message RAM. memory-region: - minItems: 1 + maxItems: 1 description: Reference to the reserved-memory for the Hexagon core smd-edge: false @@ -52,6 +52,7 @@ properties: required: - compatible - reg + - memory-region allOf: - $ref: /schemas/remoteproc/qcom,pas-common.yaml# diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sm8350-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sm8350-pas.yaml index af24f9a3cdf11..4394dfd2d8e62 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,sm8350-pas.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,sm8350-pas.yaml @@ -43,7 +43,7 @@ properties: smd-edge: false memory-region: - minItems: 1 + maxItems: 1 description: Reference to the reserved-memory for the Hexagon core firmware-name: @@ -53,6 +53,7 @@ properties: required: - compatible - reg + - memory-region allOf: - $ref: /schemas/remoteproc/qcom,pas-common.yaml# -- GitLab From 66530ffe964ce35da6e8d3787c5620b4fba5a9f9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 13 Jul 2023 09:22:40 +0200 Subject: [PATCH 0217/3445] dt-bindings: remoteproc: qcom,sm6115-pas: correct memory-region constraints Qualcomm PAS devices expect exactly one memory region, not many. Also, the memory-region is now defined in device specific binding, not in qcom,pas-common.yaml, thus also require it in the same place. Fixes: 838c558bb8bc ("dt-bindings: remoteproc: qcom: Add sm6115 pas yaml file") Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230713072242.11268-3-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- .../devicetree/bindings/remoteproc/qcom,sm6115-pas.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sm6115-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sm6115-pas.yaml index f5d1fa9f45f13..1ac5b99b2fad3 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,sm6115-pas.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,sm6115-pas.yaml @@ -32,7 +32,7 @@ properties: - const: xo memory-region: - minItems: 1 + maxItems: 1 description: Reference to the reserved-memory for the Hexagon core smd-edge: false @@ -44,6 +44,7 @@ properties: required: - compatible - reg + - memory-region allOf: - $ref: /schemas/remoteproc/qcom,pas-common.yaml# -- GitLab From ed8503220bdd86840eadc5795ae4583c62dd9739 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 13 Jul 2023 09:22:41 +0200 Subject: [PATCH 0218/3445] dt-bindings: remoteproc: qcom,sm8550-pas: require memory-region The memory-region is defined in device specific binding, not in qcom,pas-common.yaml, thus also require it in the same place. Fixes: 084258d60712 ("dt-bindings: remoteproc: qcom: adsp: document sm8550 adsp, cdsp & mpss compatible") Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230713072242.11268-4-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- .../devicetree/bindings/remoteproc/qcom,sm8550-pas.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sm8550-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sm8550-pas.yaml index fe216aa531ede..58120829fb06f 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,sm8550-pas.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,sm8550-pas.yaml @@ -53,6 +53,7 @@ properties: required: - compatible - reg + - memory-region allOf: - $ref: /schemas/remoteproc/qcom,pas-common.yaml# -- GitLab From 3aacc3b2e4ea862c21de5a0efbfa8cd59192bc43 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 13 Jul 2023 09:22:42 +0200 Subject: [PATCH 0219/3445] dt-bindings: remoteproc: qcom,adsp: bring back firmware-name The firmware-name property was moved from common qcom,pas-common.yaml binding to each device-specific schema, but the qcom,adsp.yaml was not updated. Fixes: cee616c68846 ("dt-bindings: remoteproc: qcom: adsp: move memory-region and firmware-name out of pas-common") Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230713072242.11268-5-krzysztof.kozlowski@linaro.org Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml index b571efe6d5502..2edadba91dfca 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml @@ -44,6 +44,10 @@ properties: maxItems: 1 description: Reference to the reserved-memory for the Hexagon core + firmware-name: + maxItems: 1 + description: Firmware name for the Hexagon core + required: - compatible - memory-region -- GitLab From 8ce49c2a2aa53afde9a20a8ce02b069d3b262af0 Mon Sep 17 00:00:00 2001 From: Deepak Kumar Singh Date: Fri, 7 Jul 2023 03:11:36 +0530 Subject: [PATCH 0220/3445] rpmsg: core: Add signal API support Some transports like Glink support the state notifications between clients using flow control signals similar to serial protocol signals. Local glink client drivers can send and receive flow control status to glink clients running on remote processors. Add APIs to support sending and receiving of flow control status by rpmsg clients. Signed-off-by: Deepak Kumar Singh Signed-off-by: Sarannya S Acked-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/1688679698-31274-2-git-send-email-quic_sarannya@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/rpmsg/rpmsg_core.c | 21 +++++++++++++++++++++ drivers/rpmsg/rpmsg_internal.h | 2 ++ include/linux/rpmsg.h | 15 +++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index 5039df757127a..32b550c91d9f1 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -330,6 +330,25 @@ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, } EXPORT_SYMBOL(rpmsg_trysend_offchannel); +/** + * rpmsg_set_flow_control() - request remote to pause/resume transmission + * @ept: the rpmsg endpoint + * @pause: pause transmission + * @dst: destination address of the endpoint + * + * Return: 0 on success and an appropriate error value on failure. + */ +int rpmsg_set_flow_control(struct rpmsg_endpoint *ept, bool pause, u32 dst) +{ + if (WARN_ON(!ept)) + return -EINVAL; + if (!ept->ops->set_flow_control) + return -EOPNOTSUPP; + + return ept->ops->set_flow_control(ept, pause, dst); +} +EXPORT_SYMBOL_GPL(rpmsg_set_flow_control); + /** * rpmsg_get_mtu() - get maximum transmission buffer size for sending message. * @ept: the rpmsg endpoint @@ -539,6 +558,8 @@ static int rpmsg_dev_probe(struct device *dev) rpdev->ept = ept; rpdev->src = ept->addr; + + ept->flow_cb = rpdrv->flowcontrol; } err = rpdrv->probe(rpdev); diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h index 39b646d0d40d7..b950d6f790a34 100644 --- a/drivers/rpmsg/rpmsg_internal.h +++ b/drivers/rpmsg/rpmsg_internal.h @@ -55,6 +55,7 @@ struct rpmsg_device_ops { * @trysendto: see @rpmsg_trysendto(), optional * @trysend_offchannel: see @rpmsg_trysend_offchannel(), optional * @poll: see @rpmsg_poll(), optional + * @set_flow_control: see @rpmsg_set_flow_control(), optional * @get_mtu: see @rpmsg_get_mtu(), optional * * Indirection table for the operations that a rpmsg backend should implement. @@ -75,6 +76,7 @@ struct rpmsg_endpoint_ops { void *data, int len); __poll_t (*poll)(struct rpmsg_endpoint *ept, struct file *filp, poll_table *wait); + int (*set_flow_control)(struct rpmsg_endpoint *ept, bool pause, u32 dst); ssize_t (*get_mtu)(struct rpmsg_endpoint *ept); }; diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h index 523c98b96cb41..90d8e4475f80e 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -64,12 +64,14 @@ struct rpmsg_device { }; typedef int (*rpmsg_rx_cb_t)(struct rpmsg_device *, void *, int, void *, u32); +typedef int (*rpmsg_flowcontrol_cb_t)(struct rpmsg_device *, void *, bool); /** * struct rpmsg_endpoint - binds a local rpmsg address to its user * @rpdev: rpmsg channel device * @refcount: when this drops to zero, the ept is deallocated * @cb: rx callback handler + * @flow_cb: remote flow control callback handler * @cb_lock: must be taken before accessing/changing @cb * @addr: local rpmsg address * @priv: private data for the driver's use @@ -92,6 +94,7 @@ struct rpmsg_endpoint { struct rpmsg_device *rpdev; struct kref refcount; rpmsg_rx_cb_t cb; + rpmsg_flowcontrol_cb_t flow_cb; struct mutex cb_lock; u32 addr; void *priv; @@ -106,6 +109,7 @@ struct rpmsg_endpoint { * @probe: invoked when a matching rpmsg channel (i.e. device) is found * @remove: invoked when the rpmsg channel is removed * @callback: invoked when an inbound message is received on the channel + * @flowcontrol: invoked when remote side flow control request is received */ struct rpmsg_driver { struct device_driver drv; @@ -113,6 +117,7 @@ struct rpmsg_driver { int (*probe)(struct rpmsg_device *dev); void (*remove)(struct rpmsg_device *dev); int (*callback)(struct rpmsg_device *, void *, int, void *, u32); + int (*flowcontrol)(struct rpmsg_device *, void *, bool); }; static inline u16 rpmsg16_to_cpu(struct rpmsg_device *rpdev, __rpmsg16 val) @@ -192,6 +197,8 @@ __poll_t rpmsg_poll(struct rpmsg_endpoint *ept, struct file *filp, ssize_t rpmsg_get_mtu(struct rpmsg_endpoint *ept); +int rpmsg_set_flow_control(struct rpmsg_endpoint *ept, bool pause, u32 dst); + #else static inline int rpmsg_register_device_override(struct rpmsg_device *rpdev, @@ -316,6 +323,14 @@ static inline ssize_t rpmsg_get_mtu(struct rpmsg_endpoint *ept) return -ENXIO; } +static inline int rpmsg_set_flow_control(struct rpmsg_endpoint *ept, bool pause, u32 dst) +{ + /* This shouldn't be possible */ + WARN_ON(1); + + return -ENXIO; +} + #endif /* IS_ENABLED(CONFIG_RPMSG) */ /* use a macro to avoid include chaining to get THIS_MODULE */ -- GitLab From a2b73aa512a4a90dda7dd5bb38b26b4f1381adbb Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Fri, 7 Jul 2023 03:11:37 +0530 Subject: [PATCH 0221/3445] rpmsg: glink: Add support to handle signals command Remote peripherals send signal notifications over glink with commandID 15. Add support to send and receive the signal command and based signals enable or disable flow control with remote host. Signed-off-by: Chris Lew Signed-off-by: Deepak Kumar Singh Signed-off-by: Sarannya S Acked-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/1688679698-31274-3-git-send-email-quic_sarannya@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/rpmsg/qcom_glink_native.c | 55 +++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 1beb40a1d3df2..2db82f67e6893 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -200,9 +200,15 @@ static const struct rpmsg_endpoint_ops glink_endpoint_ops; #define GLINK_CMD_TX_DATA_CONT 12 #define GLINK_CMD_READ_NOTIF 13 #define GLINK_CMD_RX_DONE_W_REUSE 14 +#define GLINK_CMD_SIGNALS 15 #define GLINK_FEATURE_INTENTLESS BIT(1) +#define NATIVE_DTR_SIG NATIVE_DSR_SIG +#define NATIVE_DSR_SIG BIT(31) +#define NATIVE_RTS_SIG NATIVE_CTS_SIG +#define NATIVE_CTS_SIG BIT(30) + static void qcom_glink_rx_done_work(struct work_struct *work); static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, @@ -1025,6 +1031,50 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid) return 0; } +/** + * qcom_glink_set_flow_control() - convert a signal cmd to wire format and transmit + * @ept: Rpmsg endpoint for channel. + * @pause: Pause transmission + * @dst: destination address of the endpoint + * + * Return: 0 on success or standard Linux error code. + */ +static int qcom_glink_set_flow_control(struct rpmsg_endpoint *ept, bool pause, u32 dst) +{ + struct glink_channel *channel = to_glink_channel(ept); + struct qcom_glink *glink = channel->glink; + struct glink_msg msg; + u32 sigs = 0; + + if (pause) + sigs |= NATIVE_DTR_SIG | NATIVE_RTS_SIG; + + msg.cmd = cpu_to_le16(GLINK_CMD_SIGNALS); + msg.param1 = cpu_to_le16(channel->lcid); + msg.param2 = cpu_to_le32(sigs); + + return qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true); +} + +static void qcom_glink_handle_signals(struct qcom_glink *glink, + unsigned int rcid, unsigned int sigs) +{ + struct glink_channel *channel; + unsigned long flags; + bool enable; + + spin_lock_irqsave(&glink->idr_lock, flags); + channel = idr_find(&glink->rcids, rcid); + spin_unlock_irqrestore(&glink->idr_lock, flags); + if (!channel) + dev_err(glink->dev, "signal for non-existing channel\n"); + + enable = sigs & NATIVE_DSR_SIG || sigs & NATIVE_CTS_SIG; + + if (channel->ept.flow_cb) + channel->ept.flow_cb(channel->ept.rpdev, channel->ept.priv, enable); +} + void qcom_glink_native_rx(struct qcom_glink *glink) { struct glink_msg msg; @@ -1086,6 +1136,10 @@ void qcom_glink_native_rx(struct qcom_glink *glink) qcom_glink_handle_intent_req_ack(glink, param1, param2); qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8)); break; + case GLINK_CMD_SIGNALS: + qcom_glink_handle_signals(glink, param1, param2); + qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8)); + break; default: dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd); ret = -EINVAL; @@ -1446,6 +1500,7 @@ static const struct rpmsg_endpoint_ops glink_endpoint_ops = { .sendto = qcom_glink_sendto, .trysend = qcom_glink_trysend, .trysendto = qcom_glink_trysendto, + .set_flow_control = qcom_glink_set_flow_control, }; static void qcom_glink_rpdev_release(struct device *dev) -- GitLab From 5550201c0fe26a76c53983bd36a58d4c4395ec22 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Fri, 7 Jul 2023 03:11:38 +0530 Subject: [PATCH 0222/3445] rpmsg: char: Add RPMSG GET/SET FLOWCONTROL IOCTL support Add RPMSG_GET_OUTGOING_FLOWCONTROL and RPMSG_SET_INCOMING_FLOWCONTROL IOCTL support for rpmsg char device nodes to get/set the low level transport signals. Signed-off-by: Chris Lew Signed-off-by: Deepak Kumar Singh Signed-off-by: Sarannya S Acked-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/1688679698-31274-4-git-send-email-quic_sarannya@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/rpmsg/rpmsg_char.c | 54 +++++++++++++++++++++++++++++++++----- include/uapi/linux/rpmsg.h | 10 +++++++ 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index a271fceb16f42..09833ad05da75 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -52,6 +52,8 @@ static DEFINE_IDA(rpmsg_minor_ida); * @readq: wait object for incoming queue * @default_ept: set to channel default endpoint if the default endpoint should be re-used * on device open to prevent endpoint address update. + * remote_flow_restricted: to indicate if the remote has requested for flow to be limited + * remote_flow_updated: to indicate if the flow control has been requested */ struct rpmsg_eptdev { struct device dev; @@ -68,6 +70,8 @@ struct rpmsg_eptdev { struct sk_buff_head queue; wait_queue_head_t readq; + bool remote_flow_restricted; + bool remote_flow_updated; }; int rpmsg_chrdev_eptdev_destroy(struct device *dev, void *data) @@ -116,6 +120,18 @@ static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len, return 0; } +static int rpmsg_ept_flow_cb(struct rpmsg_device *rpdev, void *priv, bool enable) +{ + struct rpmsg_eptdev *eptdev = priv; + + eptdev->remote_flow_restricted = enable; + eptdev->remote_flow_updated = true; + + wake_up_interruptible(&eptdev->readq); + + return 0; +} + static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) { struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev); @@ -152,6 +168,7 @@ static int rpmsg_eptdev_open(struct inode *inode, struct file *filp) return -EINVAL; } + ept->flow_cb = rpmsg_ept_flow_cb; eptdev->ept = ept; filp->private_data = eptdev; mutex_unlock(&eptdev->ept_lock); @@ -172,6 +189,7 @@ static int rpmsg_eptdev_release(struct inode *inode, struct file *filp) eptdev->ept = NULL; } mutex_unlock(&eptdev->ept_lock); + eptdev->remote_flow_updated = false; /* Discard all SKBs */ skb_queue_purge(&eptdev->queue); @@ -285,6 +303,9 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait) if (!skb_queue_empty(&eptdev->queue)) mask |= EPOLLIN | EPOLLRDNORM; + if (eptdev->remote_flow_updated) + mask |= EPOLLPRI; + mutex_lock(&eptdev->ept_lock); mask |= rpmsg_poll(eptdev->ept, filp, wait); mutex_unlock(&eptdev->ept_lock); @@ -297,14 +318,35 @@ static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd, { struct rpmsg_eptdev *eptdev = fp->private_data; - if (cmd != RPMSG_DESTROY_EPT_IOCTL) - return -EINVAL; + bool set; + int ret; - /* Don't allow to destroy a default endpoint. */ - if (eptdev->default_ept) - return -EINVAL; + switch (cmd) { + case RPMSG_GET_OUTGOING_FLOWCONTROL: + eptdev->remote_flow_updated = false; + ret = put_user(eptdev->remote_flow_restricted, (int __user *)arg); + break; + case RPMSG_SET_INCOMING_FLOWCONTROL: + if (arg > 1) { + ret = -EINVAL; + break; + } + set = !!arg; + ret = rpmsg_set_flow_control(eptdev->ept, set, eptdev->chinfo.dst); + break; + case RPMSG_DESTROY_EPT_IOCTL: + /* Don't allow to destroy a default endpoint. */ + if (eptdev->default_ept) { + ret = -EINVAL; + break; + } + ret = rpmsg_chrdev_eptdev_destroy(&eptdev->dev, NULL); + break; + default: + ret = -EINVAL; + } - return rpmsg_chrdev_eptdev_destroy(&eptdev->dev, NULL); + return ret; } static const struct file_operations rpmsg_eptdev_fops = { diff --git a/include/uapi/linux/rpmsg.h b/include/uapi/linux/rpmsg.h index 1637e68177d9d..f0c8da2b185b4 100644 --- a/include/uapi/linux/rpmsg.h +++ b/include/uapi/linux/rpmsg.h @@ -43,4 +43,14 @@ struct rpmsg_endpoint_info { */ #define RPMSG_RELEASE_DEV_IOCTL _IOW(0xb5, 0x4, struct rpmsg_endpoint_info) +/** + * Get the flow control state of the remote rpmsg char device. + */ +#define RPMSG_GET_OUTGOING_FLOWCONTROL _IOR(0xb5, 0x5, int) + +/** + * Set the flow control state of the local rpmsg char device. + */ +#define RPMSG_SET_INCOMING_FLOWCONTROL _IOR(0xb5, 0x6, int) + #endif -- GitLab From 0b6c3bc88bd920d2e89921cd308a0276f05ad8c7 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 29 Jun 2023 17:33:27 +0800 Subject: [PATCH 0223/3445] remoteproc: imx_rproc: iterate all notifiyids in rx callback The current code only supports one vdev and a single callback, but there are cases need more vdevs. So iterate all notifyids to support more vdevs with the single callback. Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20230629093327.3376308-1-peng.fan@oss.nxp.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/imx_rproc.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index b403a37ddb02e..4ee2646ce62ad 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -725,13 +725,22 @@ static int imx_rproc_addr_init(struct imx_rproc *priv, return 0; } +static int imx_rproc_notified_idr_cb(int id, void *ptr, void *data) +{ + struct rproc *rproc = data; + + rproc_vq_interrupt(rproc, id); + + return 0; +} + static void imx_rproc_vq_work(struct work_struct *work) { struct imx_rproc *priv = container_of(work, struct imx_rproc, rproc_work); + struct rproc *rproc = priv->rproc; - rproc_vq_interrupt(priv->rproc, 0); - rproc_vq_interrupt(priv->rproc, 1); + idr_for_each(&rproc->notifyids, imx_rproc_notified_idr_cb, rproc); } static void imx_rproc_rx_callback(struct mbox_client *cl, void *msg) -- GitLab From 0ee55c188a3c97309a6794077d5ef4ebd58f62cb Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 10 Jul 2023 22:34:52 +0200 Subject: [PATCH 0224/3445] remoteproc: qcom: Use of_reserved_mem_lookup() Reserved memory can be either looked up using the generic function of_address_to_resource() or using the special of_reserved_mem_lookup(). The latter has the advantage that it ensures that the referenced memory region was really reserved and is not e.g. status = "disabled". of_reserved_mem also supports allocating reserved memory dynamically at boot time. This works only when using of_reserved_mem_lookup() since there won't be a fixed address in the device tree. Switch the code to use of_reserved_mem_lookup(), similar to qcom_q6v5_wcss.c which is using it already. There is no functional difference for static reserved memory allocations. While at it this also adds two missing of_node_put() calls in qcom_q6v5_pas.c. Signed-off-by: Stephan Gerhold Tested-by: Caleb Connolly # SDM845 Reviewed-by: Caleb Connolly Link: https://lore.kernel.org/r/20230710-rproc-of-rmem-v3-1-eea7f0a33590@gerhold.net Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_adsp.c | 24 +++++++------- drivers/remoteproc/qcom_q6v5_mss.c | 33 +++++++++++-------- drivers/remoteproc/qcom_q6v5_pas.c | 50 ++++++++++++++++------------- drivers/remoteproc/qcom_wcnss.c | 24 +++++++------- 4 files changed, 69 insertions(+), 62 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c index 7733be477db58..6c67514cc4931 100644 --- a/drivers/remoteproc/qcom_q6v5_adsp.c +++ b/drivers/remoteproc/qcom_q6v5_adsp.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include @@ -637,28 +637,26 @@ static int adsp_init_mmio(struct qcom_adsp *adsp, static int adsp_alloc_memory_region(struct qcom_adsp *adsp) { + struct reserved_mem *rmem = NULL; struct device_node *node; - struct resource r; - int ret; node = of_parse_phandle(adsp->dev->of_node, "memory-region", 0); - if (!node) { - dev_err(adsp->dev, "no memory-region specified\n"); + if (node) + rmem = of_reserved_mem_lookup(node); + of_node_put(node); + + if (!rmem) { + dev_err(adsp->dev, "unable to resolve memory-region\n"); return -EINVAL; } - ret = of_address_to_resource(node, 0, &r); - of_node_put(node); - if (ret) - return ret; - - adsp->mem_phys = adsp->mem_reloc = r.start; - adsp->mem_size = resource_size(&r); + adsp->mem_phys = adsp->mem_reloc = rmem->base; + adsp->mem_size = rmem->size; adsp->mem_region = devm_ioremap_wc(adsp->dev, adsp->mem_phys, adsp->mem_size); if (!adsp->mem_region) { dev_err(adsp->dev, "unable to map memory region: %pa+%zx\n", - &r.start, adsp->mem_size); + &rmem->base, adsp->mem_size); return -EBUSY; } diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 76c546871a949..6e333c5e65a94 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -1876,8 +1875,6 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc) struct device_node *child; struct reserved_mem *rmem; struct device_node *node; - struct resource r; - int ret; /* * In the absence of mba/mpss sub-child, extract the mba and mpss @@ -1892,15 +1889,20 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc) of_node_put(child); } - ret = of_address_to_resource(node, 0, &r); + if (!node) { + dev_err(qproc->dev, "no mba memory-region specified\n"); + return -EINVAL; + } + + rmem = of_reserved_mem_lookup(node); of_node_put(node); - if (ret) { + if (!rmem) { dev_err(qproc->dev, "unable to resolve mba region\n"); - return ret; + return -EINVAL; } - qproc->mba_phys = r.start; - qproc->mba_size = resource_size(&r); + qproc->mba_phys = rmem->base; + qproc->mba_size = rmem->size; if (!child) { node = of_parse_phandle(qproc->dev->of_node, @@ -1911,15 +1913,20 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc) of_node_put(child); } - ret = of_address_to_resource(node, 0, &r); + if (!node) { + dev_err(qproc->dev, "no mpss memory-region specified\n"); + return -EINVAL; + } + + rmem = of_reserved_mem_lookup(node); of_node_put(node); - if (ret) { + if (!rmem) { dev_err(qproc->dev, "unable to resolve mpss region\n"); - return ret; + return -EINVAL; } - qproc->mpss_phys = qproc->mpss_reloc = r.start; - qproc->mpss_size = resource_size(&r); + qproc->mpss_phys = qproc->mpss_reloc = rmem->base; + qproc->mpss_size = rmem->size; if (!child) { node = of_parse_phandle(qproc->dev->of_node, "memory-region", 2); diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index faec3a3d8e4ef..0caedb0905479 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -533,9 +534,8 @@ static void adsp_pds_detach(struct qcom_adsp *adsp, struct device **pds, static int adsp_alloc_memory_region(struct qcom_adsp *adsp) { + struct reserved_mem *rmem; struct device_node *node; - struct resource r; - int ret; node = of_parse_phandle(adsp->dev->of_node, "memory-region", 0); if (!node) { @@ -543,17 +543,19 @@ static int adsp_alloc_memory_region(struct qcom_adsp *adsp) return -EINVAL; } - ret = of_address_to_resource(node, 0, &r); + rmem = of_reserved_mem_lookup(node); of_node_put(node); - if (ret) - return ret; + if (!rmem) { + dev_err(adsp->dev, "unable to resolve memory-region\n"); + return -EINVAL; + } - adsp->mem_phys = adsp->mem_reloc = r.start; - adsp->mem_size = resource_size(&r); + adsp->mem_phys = adsp->mem_reloc = rmem->base; + adsp->mem_size = rmem->size; adsp->mem_region = devm_ioremap_wc(adsp->dev, adsp->mem_phys, adsp->mem_size); if (!adsp->mem_region) { dev_err(adsp->dev, "unable to map memory region: %pa+%zx\n", - &r.start, adsp->mem_size); + &rmem->base, adsp->mem_size); return -EBUSY; } @@ -566,16 +568,19 @@ static int adsp_alloc_memory_region(struct qcom_adsp *adsp) return -EINVAL; } - ret = of_address_to_resource(node, 0, &r); - if (ret) - return ret; + rmem = of_reserved_mem_lookup(node); + of_node_put(node); + if (!rmem) { + dev_err(adsp->dev, "unable to resolve dtb memory-region\n"); + return -EINVAL; + } - adsp->dtb_mem_phys = adsp->dtb_mem_reloc = r.start; - adsp->dtb_mem_size = resource_size(&r); + adsp->dtb_mem_phys = adsp->dtb_mem_reloc = rmem->base; + adsp->dtb_mem_size = rmem->size; adsp->dtb_mem_region = devm_ioremap_wc(adsp->dev, adsp->dtb_mem_phys, adsp->dtb_mem_size); if (!adsp->dtb_mem_region) { dev_err(adsp->dev, "unable to map dtb memory region: %pa+%zx\n", - &r.start, adsp->dtb_mem_size); + &rmem->base, adsp->dtb_mem_size); return -EBUSY; } @@ -584,29 +589,28 @@ static int adsp_alloc_memory_region(struct qcom_adsp *adsp) static int adsp_assign_memory_region(struct qcom_adsp *adsp) { + struct reserved_mem *rmem = NULL; struct qcom_scm_vmperm perm; struct device_node *node; - struct resource r; int ret; if (!adsp->region_assign_idx) return 0; node = of_parse_phandle(adsp->dev->of_node, "memory-region", adsp->region_assign_idx); - if (!node) { - dev_err(adsp->dev, "missing shareable memory-region\n"); + if (node) + rmem = of_reserved_mem_lookup(node); + of_node_put(node); + if (!rmem) { + dev_err(adsp->dev, "unable to resolve shareable memory-region\n"); return -EINVAL; } - ret = of_address_to_resource(node, 0, &r); - if (ret) - return ret; - perm.vmid = QCOM_SCM_VMID_MSS_MSA; perm.perm = QCOM_SCM_PERM_RW; - adsp->region_assign_phys = r.start; - adsp->region_assign_size = resource_size(&r); + adsp->region_assign_phys = rmem->base; + adsp->region_assign_size = rmem->size; adsp->region_assign_perms = BIT(QCOM_SCM_VMID_HLOS); ret = qcom_scm_assign_mem(adsp->region_assign_phys, diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index c109096bbfe33..af42517fde081 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include @@ -506,27 +506,25 @@ static int wcnss_request_irq(struct qcom_wcnss *wcnss, static int wcnss_alloc_memory_region(struct qcom_wcnss *wcnss) { + struct reserved_mem *rmem = NULL; struct device_node *node; - struct resource r; - int ret; node = of_parse_phandle(wcnss->dev->of_node, "memory-region", 0); - if (!node) { - dev_err(wcnss->dev, "no memory-region specified\n"); + if (node) + rmem = of_reserved_mem_lookup(node); + of_node_put(node); + + if (!rmem) { + dev_err(wcnss->dev, "unable to resolve memory-region\n"); return -EINVAL; } - ret = of_address_to_resource(node, 0, &r); - of_node_put(node); - if (ret) - return ret; - - wcnss->mem_phys = wcnss->mem_reloc = r.start; - wcnss->mem_size = resource_size(&r); + wcnss->mem_phys = wcnss->mem_reloc = rmem->base; + wcnss->mem_size = rmem->size; wcnss->mem_region = devm_ioremap_wc(wcnss->dev, wcnss->mem_phys, wcnss->mem_size); if (!wcnss->mem_region) { dev_err(wcnss->dev, "unable to map memory region: %pa+%zx\n", - &r.start, wcnss->mem_size); + &rmem->base, wcnss->mem_size); return -EBUSY; } -- GitLab From f247f08da0ce822de0d6b2feec811dd6d4d599ce Mon Sep 17 00:00:00 2001 From: Siddharth Gupta Date: Fri, 24 Feb 2023 13:17:06 -0800 Subject: [PATCH 0225/3445] remoteproc: core: Export the rproc coredump APIs The remoteproc coredump APIs are currently only part of the internal remoteproc header. This prevents the remoteproc platform drivers from using these APIs when needed. This change moves the rproc_coredump() and rproc_coredump_cleanup() APIs to the linux header and marks them as exported symbols. Signed-off-by: Siddharth Gupta Signed-off-by: Gokul krishna Krishnakumar Link: https://lore.kernel.org/r/20230224211707.30916-2-quic_gokukris@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/remoteproc_coredump.c | 2 ++ drivers/remoteproc/remoteproc_internal.h | 4 ---- include/linux/remoteproc.h | 4 ++++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/remoteproc/remoteproc_coredump.c b/drivers/remoteproc/remoteproc_coredump.c index bc0e1603a7a3f..6ede8c0c93ad5 100644 --- a/drivers/remoteproc/remoteproc_coredump.c +++ b/drivers/remoteproc/remoteproc_coredump.c @@ -32,6 +32,7 @@ void rproc_coredump_cleanup(struct rproc *rproc) kfree(entry); } } +EXPORT_SYMBOL_GPL(rproc_coredump_cleanup); /** * rproc_coredump_add_segment() - add segment of device memory to coredump @@ -327,6 +328,7 @@ void rproc_coredump(struct rproc *rproc) */ wait_for_completion(&dump_state.dump_done); } +EXPORT_SYMBOL_GPL(rproc_coredump); /** * rproc_coredump_using_sections() - perform coredump using section headers diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h index d4dbb8d1d80cc..f62a82d71dfaa 100644 --- a/drivers/remoteproc/remoteproc_internal.h +++ b/drivers/remoteproc/remoteproc_internal.h @@ -76,10 +76,6 @@ extern struct class rproc_class; int rproc_init_sysfs(void); void rproc_exit_sysfs(void); -/* from remoteproc_coredump.c */ -void rproc_coredump_cleanup(struct rproc *rproc); -void rproc_coredump(struct rproc *rproc); - #ifdef CONFIG_REMOTEPROC_CDEV void rproc_init_cdev(void); void rproc_exit_cdev(void); diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index fe8978eb69f1c..b4795698d8c2a 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -690,6 +690,10 @@ int rproc_detach(struct rproc *rproc); int rproc_set_firmware(struct rproc *rproc, const char *fw_name); void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type); void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem); + +/* from remoteproc_coredump.c */ +void rproc_coredump_cleanup(struct rproc *rproc); +void rproc_coredump(struct rproc *rproc); void rproc_coredump_using_sections(struct rproc *rproc); int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size); int rproc_coredump_add_custom_segment(struct rproc *rproc, -- GitLab From 5c43ed8ad20b29c89991c03d4c84afb9c53608a3 Mon Sep 17 00:00:00 2001 From: Siddharth Gupta Date: Fri, 24 Feb 2023 13:17:07 -0800 Subject: [PATCH 0226/3445] remoteproc: qcom: Add full coredump fallback mechanism If a remoteproc's firmware does not support minidump but the driver adds an ID, the minidump driver does not collect any coredumps when the remoteproc crashes. This hinders the purpose of coredump collection. This change adds a fallback mechanism in the event of a crash. Signed-off-by: Siddharth Gupta Signed-off-by: Gokul krishna Krishnakumar Link: https://lore.kernel.org/r/20230224211707.30916-3-quic_gokukris@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_common.c | 13 +++++++++++-- drivers/remoteproc/qcom_q6v5_pas.c | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index a0d4238492e90..4bbb47dda05ec 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -168,12 +168,21 @@ void qcom_minidump(struct rproc *rproc, unsigned int minidump_id, */ if (subsystem->regions_baseptr == 0 || le32_to_cpu(subsystem->status) != 1 || - le32_to_cpu(subsystem->enabled) != MD_SS_ENABLED || - le32_to_cpu(subsystem->encryption_status) != MD_SS_ENCR_DONE) { + le32_to_cpu(subsystem->enabled) != MD_SS_ENABLED) { + return rproc_coredump(rproc); + } + + if (le32_to_cpu(subsystem->encryption_status) != MD_SS_ENCR_DONE) { dev_err(&rproc->dev, "Minidump not ready, skipping\n"); return; } + /** + * Clear out the dump segments populated by parse_fw before + * re-populating them with minidump segments. + */ + rproc_coredump_cleanup(rproc); + ret = qcom_add_minidump_segments(rproc, subsystem, rproc_dumpfn_t); if (ret) { dev_err(&rproc->dev, "Failed with error: %d while adding minidump entries\n", ret); diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 0caedb0905479..d5b62066743fe 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -426,6 +426,7 @@ static const struct rproc_ops adsp_minidump_ops = { .start = adsp_start, .stop = adsp_stop, .da_to_va = adsp_da_to_va, + .parse_fw = qcom_register_dump_segments, .load = adsp_load, .panic = adsp_panic, .coredump = adsp_minidump, -- GitLab From 3c81195a04e13833196462ab398d8bcf282701f7 Mon Sep 17 00:00:00 2001 From: Kang Chen Date: Mon, 27 Feb 2023 08:41:16 +0800 Subject: [PATCH 0227/3445] hwspinlock: add a check of devm_regmap_field_alloc in qcom_hwspinlock_probe devm_regmap_field_alloc may fails, priv field might be error pointer and cause illegal address access later. Signed-off-by: Kang Chen Link: https://lore.kernel.org/r/20230227004116.1273988-1-void0red@gmail.com Signed-off-by: Bjorn Andersson --- drivers/hwspinlock/qcom_hwspinlock.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hwspinlock/qcom_hwspinlock.c b/drivers/hwspinlock/qcom_hwspinlock.c index 9cf186362ae2f..dee7bb5eae382 100644 --- a/drivers/hwspinlock/qcom_hwspinlock.c +++ b/drivers/hwspinlock/qcom_hwspinlock.c @@ -197,6 +197,8 @@ static int qcom_hwspinlock_probe(struct platform_device *pdev) bank->lock[i].priv = devm_regmap_field_alloc(&pdev->dev, regmap, field); + if (IS_ERR(bank->lock[i].priv)) + return PTR_ERR(bank->lock[i].priv); } return devm_hwspin_lock_register(&pdev->dev, bank, &qcom_hwspinlock_ops, -- GitLab From 72a3a509f992b6bd182b3380913fe7b4f801075f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 14 Mar 2023 19:00:59 +0100 Subject: [PATCH 0228/3445] hwspinlock: omap: Emit only one error message for errors in .remove() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a remove callback of a platform driver returns a non-zero value, the driver core emits an error message, otherwise ignores the value and completes unbinding the device. As omap_hwspinlock_remove() already emits an error message, suppress the core's error message by returning zero. Signed-off-by: Uwe Kleine-König Acked-by: Baolin Wang Link: https://lore.kernel.org/r/20230314180100.2865801-1-u.kleine-koenig@pengutronix.de Signed-off-by: Bjorn Andersson --- drivers/hwspinlock/omap_hwspinlock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwspinlock/omap_hwspinlock.c b/drivers/hwspinlock/omap_hwspinlock.c index dfe82952671b1..a2538c67396f4 100644 --- a/drivers/hwspinlock/omap_hwspinlock.c +++ b/drivers/hwspinlock/omap_hwspinlock.c @@ -153,7 +153,7 @@ static int omap_hwspinlock_remove(struct platform_device *pdev) ret = hwspin_lock_unregister(bank); if (ret) { dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret); - return ret; + return 0; } pm_runtime_disable(&pdev->dev); -- GitLab From 4cf16b6b743e0bbe3128cf97a193ee37110d597b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 14 Mar 2023 19:01:00 +0100 Subject: [PATCH 0229/3445] hwspinlock: omap: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Baolin Wang Link: https://lore.kernel.org/r/20230314180100.2865801-2-u.kleine-koenig@pengutronix.de Signed-off-by: Bjorn Andersson --- drivers/hwspinlock/omap_hwspinlock.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/hwspinlock/omap_hwspinlock.c b/drivers/hwspinlock/omap_hwspinlock.c index a2538c67396f4..a9fd9ca45f2a8 100644 --- a/drivers/hwspinlock/omap_hwspinlock.c +++ b/drivers/hwspinlock/omap_hwspinlock.c @@ -145,7 +145,7 @@ runtime_err: return ret; } -static int omap_hwspinlock_remove(struct platform_device *pdev) +static void omap_hwspinlock_remove(struct platform_device *pdev) { struct hwspinlock_device *bank = platform_get_drvdata(pdev); int ret; @@ -153,12 +153,10 @@ static int omap_hwspinlock_remove(struct platform_device *pdev) ret = hwspin_lock_unregister(bank); if (ret) { dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret); - return 0; + return; } pm_runtime_disable(&pdev->dev); - - return 0; } static const struct of_device_id omap_hwspinlock_of_match[] = { @@ -171,7 +169,7 @@ MODULE_DEVICE_TABLE(of, omap_hwspinlock_of_match); static struct platform_driver omap_hwspinlock_driver = { .probe = omap_hwspinlock_probe, - .remove = omap_hwspinlock_remove, + .remove_new = omap_hwspinlock_remove, .driver = { .name = "omap_hwspinlock", .of_match_table = omap_hwspinlock_of_match, -- GitLab From 9519793bb6a731a3dd2453ad8515e8866e84c48e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 14 Mar 2023 19:02:41 +0100 Subject: [PATCH 0230/3445] hwspinlock: u8500: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is (mostly) ignored and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Linus Walleij Acked-by: Baolin Wang Link: https://lore.kernel.org/r/20230314180241.2865888-1-u.kleine-koenig@pengutronix.de Signed-off-by: Bjorn Andersson --- drivers/hwspinlock/u8500_hsem.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwspinlock/u8500_hsem.c b/drivers/hwspinlock/u8500_hsem.c index 67845c0c97012..1edca1092f29b 100644 --- a/drivers/hwspinlock/u8500_hsem.c +++ b/drivers/hwspinlock/u8500_hsem.c @@ -120,20 +120,18 @@ static int u8500_hsem_probe(struct platform_device *pdev) pdata->base_id, num_locks); } -static int u8500_hsem_remove(struct platform_device *pdev) +static void u8500_hsem_remove(struct platform_device *pdev) { struct hwspinlock_device *bank = platform_get_drvdata(pdev); void __iomem *io_base = bank->lock[0].priv - HSEM_REGISTER_OFFSET; /* clear all interrupts */ writel(0xFFFF, io_base + HSEM_ICRALL); - - return 0; } static struct platform_driver u8500_hsem_driver = { .probe = u8500_hsem_probe, - .remove = u8500_hsem_remove, + .remove_new = u8500_hsem_remove, .driver = { .name = "u8500_hsem", }, -- GitLab From b352033e19c4591df299a8f623508c5c2ce4c5b3 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 15 Mar 2023 19:32:31 +0100 Subject: [PATCH 0231/3445] dt-bindings: remoteproc: qcom: sm6115-pas: Add QCM2290 QCM2290 is more or less a fork of the same design that SM6115 is based on. As a result, the ADSP and modem found on it are identical. Add compatibles for the QCM2290 with SM6115 fallbacks so as not to require any driver changes. Change the allOf:if:properties clauses to look for the presence of SM6115 compatibles and not an exact match. Note that QCM2290 lacks a CDSP. Signed-off-by: Konrad Dybcio Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230315183231.3562580-1-konrad.dybcio@linaro.org Signed-off-by: Bjorn Andersson --- .../bindings/remoteproc/qcom,sm6115-pas.yaml | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sm6115-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sm6115-pas.yaml index 1ac5b99b2fad3..0282872359122 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,sm6115-pas.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,sm6115-pas.yaml @@ -15,10 +15,19 @@ description: properties: compatible: - enum: - - qcom,sm6115-adsp-pas - - qcom,sm6115-cdsp-pas - - qcom,sm6115-mpss-pas + oneOf: + - enum: + - qcom,sm6115-adsp-pas + - qcom,sm6115-cdsp-pas + - qcom,sm6115-mpss-pas + + - items: + - const: qcom,qcm2290-adsp-pas + - const: qcom,sm6115-adsp-pas + + - items: + - const: qcom,qcm2290-mpss-pas + - const: qcom,sm6115-mpss-pas reg: maxItems: 1 @@ -51,9 +60,10 @@ allOf: - if: properties: compatible: - enum: - - qcom,sm6115-adsp-pas - - qcom,sm6115-cdsp-pas + contains: + enum: + - qcom,sm6115-adsp-pas + - qcom,sm6115-cdsp-pas then: properties: interrupts: @@ -70,9 +80,10 @@ allOf: - if: properties: compatible: - enum: - - qcom,sm6115-cdsp-pas - - qcom,sm6115-mpss-pas + contains: + enum: + - qcom,sm6115-cdsp-pas + - qcom,sm6115-mpss-pas then: properties: power-domains: @@ -85,8 +96,9 @@ allOf: - if: properties: compatible: - enum: - - qcom,sm6115-adsp-pas + contains: + enum: + - qcom,sm6115-adsp-pas then: properties: power-domains: -- GitLab From 5b2b675adf8f302f89ad2624bc4ad2327b669ec2 Mon Sep 17 00:00:00 2001 From: Ye Xingchen Date: Wed, 22 Mar 2023 11:15:14 +0800 Subject: [PATCH 0232/3445] =?UTF-8?q?remoteproc:=20qcom:=20q6v5:=20use?= =?UTF-8?q?=C2=A0devm=5Fplatform=5Fioremap=5Fresource=5Fbyname()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert platform_get_resource_byname(),devm_ioremap_resource() to a single call to devm_platform_ioremap_resource_byname(), as this is exactly what this function does. Signed-off-by: Ye Xingchen Link: https://lore.kernel.org/r/202303221115145068959@zte.com.cn Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_wcss.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c index b437044aa1267..cff1fa07d1def 100644 --- a/drivers/remoteproc/qcom_q6v5_wcss.c +++ b/drivers/remoteproc/qcom_q6v5_wcss.c @@ -837,8 +837,7 @@ static int q6v5_wcss_init_mmio(struct q6v5_wcss *wcss, return -ENOMEM; if (wcss->version == WCSS_IPQ8074) { - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb"); - wcss->rmb_base = devm_ioremap_resource(&pdev->dev, res); + wcss->rmb_base = devm_platform_ioremap_resource_byname(pdev, "rmb"); if (IS_ERR(wcss->rmb_base)) return PTR_ERR(wcss->rmb_base); } -- GitLab From 92d24d0927bc4399cbb6bca9d7c410cd849c6a1d Mon Sep 17 00:00:00 2001 From: Ye Xingchen Date: Wed, 22 Mar 2023 11:16:42 +0800 Subject: [PATCH 0233/3445] =?UTF-8?q?remoteproc:=20qcom:=20wcnss:=20use?= =?UTF-8?q?=C2=A0devm=5Fplatform=5Fioremap=5Fresource=5Fbyname()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert platform_get_resource_byname(),devm_ioremap_resource() to a single call to devm_platform_ioremap_resource_byname(), as this is exactly what this function does. Signed-off-by: Ye Xingchen Link: https://lore.kernel.org/r/202303221116427329010@zte.com.cn Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_wcnss.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index af42517fde081..90de22c81da97 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -536,7 +536,6 @@ static int wcnss_probe(struct platform_device *pdev) const char *fw_name = WCNSS_FIRMWARE_NAME; const struct wcnss_data *data; struct qcom_wcnss *wcnss; - struct resource *res; struct rproc *rproc; void __iomem *mmio; int ret; @@ -574,8 +573,7 @@ static int wcnss_probe(struct platform_device *pdev) mutex_init(&wcnss->iris_lock); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pmu"); - mmio = devm_ioremap_resource(&pdev->dev, res); + mmio = devm_platform_ioremap_resource_byname(pdev, "pmu"); if (IS_ERR(mmio)) { ret = PTR_ERR(mmio); goto free_rproc; -- GitLab From 242a626870eb453934b75749f8dbab997556b555 Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Thu, 30 Mar 2023 18:46:31 +0200 Subject: [PATCH 0234/3445] dt-bindings: remoteproc: qcom: adsp: add qcom,sdm845-slpi-pas compatible SLPI DSP remoteproc on DSP is defined by the 'qcom,sdm845-slpi-pas' compatible in the qcom_q6v5_pas driver. Add this compatible to the devicetree bindings. Signed-off-by: Dylan Van Assche Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230330164633.117335-2-me@dylanvanassche.be Signed-off-by: Bjorn Andersson --- .../bindings/remoteproc/qcom,adsp.yaml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml index 2edadba91dfca..a2b0079de0390 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,adsp.yaml @@ -26,6 +26,7 @@ properties: - qcom,sdm660-adsp-pas - qcom,sdm845-adsp-pas - qcom,sdm845-cdsp-pas + - qcom,sdm845-slpi-pas reg: maxItems: 1 @@ -68,6 +69,7 @@ allOf: - qcom,msm8998-adsp-pas - qcom,sdm845-adsp-pas - qcom,sdm845-cdsp-pas + - qcom,sdm845-slpi-pas then: properties: clocks: @@ -109,6 +111,7 @@ allOf: - qcom,msm8998-slpi-pas - qcom,sdm845-adsp-pas - qcom,sdm845-cdsp-pas + - qcom,sdm845-slpi-pas then: properties: interrupts: @@ -162,6 +165,22 @@ allOf: required: - px-supply + - if: + properties: + compatible: + enum: + - qcom,sdm845-slpi-pas + then: + properties: + power-domains: + items: + - description: LCX power domain + - description: LMX power domain + power-domain-names: + items: + - const: lcx + - const: lmx + - if: properties: compatible: -- GitLab From 637e98bfe20b2c6866cd79b8d487430af09dc8ac Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Thu, 30 Mar 2023 18:46:32 +0200 Subject: [PATCH 0235/3445] remoteproc: qcom: pas: refactor SLPI remoteproc init SLPI remoteproc initialization is the same for SDM845, SM8150, SM8250, SM8350 but is duplicated for each compatible. Refactor initialization structs for these 4 compatibles as a single struct. Signed-off-by: Dylan Van Assche Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230330164633.117335-3-me@dylanvanassche.be Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pas.c | 48 +++++------------------------- 1 file changed, 8 insertions(+), 40 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index d5b62066743fe..8d5fb9178e304 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -1017,7 +1017,7 @@ static const struct adsp_data sc8180x_mpss_resource = { .ssctl_id = 0x12, }; -static const struct adsp_data slpi_resource_init = { +static const struct adsp_data msm8996_slpi_resource_init = { .crash_reason_smem = 424, .firmware_name = "slpi.mdt", .pas_id = 12, @@ -1031,7 +1031,7 @@ static const struct adsp_data slpi_resource_init = { .ssctl_id = 0x16, }; -static const struct adsp_data sm8150_slpi_resource = { +static const struct adsp_data sdm845_slpi_resource_init = { .crash_reason_smem = 424, .firmware_name = "slpi.mdt", .pas_id = 12, @@ -1047,38 +1047,6 @@ static const struct adsp_data sm8150_slpi_resource = { .ssctl_id = 0x16, }; -static const struct adsp_data sm8250_slpi_resource = { - .crash_reason_smem = 424, - .firmware_name = "slpi.mdt", - .pas_id = 12, - .auto_boot = true, - .proxy_pd_names = (char*[]){ - "lcx", - "lmx", - NULL - }, - .load_state = "slpi", - .ssr_name = "dsps", - .sysmon_name = "slpi", - .ssctl_id = 0x16, -}; - -static const struct adsp_data sm8350_slpi_resource = { - .crash_reason_smem = 424, - .firmware_name = "slpi.mdt", - .pas_id = 12, - .auto_boot = true, - .proxy_pd_names = (char*[]){ - "lcx", - "lmx", - NULL - }, - .load_state = "slpi", - .ssr_name = "dsps", - .sysmon_name = "slpi", - .ssctl_id = 0x16, -}; - static const struct adsp_data wcss_resource_init = { .crash_reason_smem = 421, .firmware_name = "wcnss.mdt", @@ -1187,9 +1155,9 @@ static const struct of_device_id adsp_of_match[] = { { .compatible = "qcom,msm8953-adsp-pil", .data = &msm8996_adsp_resource}, { .compatible = "qcom,msm8974-adsp-pil", .data = &adsp_resource_init}, { .compatible = "qcom,msm8996-adsp-pil", .data = &msm8996_adsp_resource}, - { .compatible = "qcom,msm8996-slpi-pil", .data = &slpi_resource_init}, + { .compatible = "qcom,msm8996-slpi-pil", .data = &msm8996_slpi_resource_init}, { .compatible = "qcom,msm8998-adsp-pas", .data = &msm8996_adsp_resource}, - { .compatible = "qcom,msm8998-slpi-pas", .data = &slpi_resource_init}, + { .compatible = "qcom,msm8998-slpi-pas", .data = &msm8996_slpi_resource_init}, { .compatible = "qcom,qcs404-adsp-pas", .data = &adsp_resource_init }, { .compatible = "qcom,qcs404-cdsp-pas", .data = &cdsp_resource_init }, { .compatible = "qcom,qcs404-wcss-pas", .data = &wcss_resource_init }, @@ -1214,17 +1182,17 @@ static const struct of_device_id adsp_of_match[] = { { .compatible = "qcom,sm8150-adsp-pas", .data = &sm8150_adsp_resource}, { .compatible = "qcom,sm8150-cdsp-pas", .data = &sm8150_cdsp_resource}, { .compatible = "qcom,sm8150-mpss-pas", .data = &mpss_resource_init}, - { .compatible = "qcom,sm8150-slpi-pas", .data = &sm8150_slpi_resource}, + { .compatible = "qcom,sm8150-slpi-pas", .data = &sdm845_slpi_resource_init}, { .compatible = "qcom,sm8250-adsp-pas", .data = &sm8250_adsp_resource}, { .compatible = "qcom,sm8250-cdsp-pas", .data = &sm8250_cdsp_resource}, - { .compatible = "qcom,sm8250-slpi-pas", .data = &sm8250_slpi_resource}, + { .compatible = "qcom,sm8250-slpi-pas", .data = &sdm845_slpi_resource_init}, { .compatible = "qcom,sm8350-adsp-pas", .data = &sm8350_adsp_resource}, { .compatible = "qcom,sm8350-cdsp-pas", .data = &sm8350_cdsp_resource}, - { .compatible = "qcom,sm8350-slpi-pas", .data = &sm8350_slpi_resource}, + { .compatible = "qcom,sm8350-slpi-pas", .data = &sdm845_slpi_resource_init}, { .compatible = "qcom,sm8350-mpss-pas", .data = &mpss_resource_init}, { .compatible = "qcom,sm8450-adsp-pas", .data = &sm8350_adsp_resource}, { .compatible = "qcom,sm8450-cdsp-pas", .data = &sm8350_cdsp_resource}, - { .compatible = "qcom,sm8450-slpi-pas", .data = &sm8350_slpi_resource}, + { .compatible = "qcom,sm8450-slpi-pas", .data = &sdm845_slpi_resource_init}, { .compatible = "qcom,sm8450-mpss-pas", .data = &sm8450_mpss_resource}, { .compatible = "qcom,sm8550-adsp-pas", .data = &sm8550_adsp_resource}, { .compatible = "qcom,sm8550-cdsp-pas", .data = &sm8550_cdsp_resource}, -- GitLab From 318da1371246fdc1806011a27138175cfb078687 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Wed, 3 May 2023 22:32:15 +0530 Subject: [PATCH 0236/3445] remoteproc: qcom: Expand MD_* as MINIDUMP_* Expand MD_* as MINIDUMP_* which makes more sense than the abbreviation. Signed-off-by: Mukesh Ojha Link: https://lore.kernel.org/r/1683133352-10046-2-git-send-email-quic_mojha@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_common.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c index 4bbb47dda05ec..03e5f5d533eb3 100644 --- a/drivers/remoteproc/qcom_common.c +++ b/drivers/remoteproc/qcom_common.c @@ -29,9 +29,9 @@ #define MAX_NUM_OF_SS 10 #define MAX_REGION_NAME_LENGTH 16 #define SBL_MINIDUMP_SMEM_ID 602 -#define MD_REGION_VALID ('V' << 24 | 'A' << 16 | 'L' << 8 | 'I' << 0) -#define MD_SS_ENCR_DONE ('D' << 24 | 'O' << 16 | 'N' << 8 | 'E' << 0) -#define MD_SS_ENABLED ('E' << 24 | 'N' << 16 | 'B' << 8 | 'L' << 0) +#define MINIDUMP_REGION_VALID ('V' << 24 | 'A' << 16 | 'L' << 8 | 'I' << 0) +#define MINIDUMP_SS_ENCR_DONE ('D' << 24 | 'O' << 16 | 'N' << 8 | 'E' << 0) +#define MINIDUMP_SS_ENABLED ('E' << 24 | 'N' << 16 | 'B' << 8 | 'L' << 0) /** * struct minidump_region - Minidump region @@ -125,7 +125,7 @@ static int qcom_add_minidump_segments(struct rproc *rproc, struct minidump_subsy for (i = 0; i < seg_cnt; i++) { memcpy_fromio(®ion, ptr + i, sizeof(region)); - if (le32_to_cpu(region.valid) == MD_REGION_VALID) { + if (le32_to_cpu(region.valid) == MINIDUMP_REGION_VALID) { name = kstrndup(region.name, MAX_REGION_NAME_LENGTH - 1, GFP_KERNEL); if (!name) { iounmap(ptr); @@ -168,11 +168,11 @@ void qcom_minidump(struct rproc *rproc, unsigned int minidump_id, */ if (subsystem->regions_baseptr == 0 || le32_to_cpu(subsystem->status) != 1 || - le32_to_cpu(subsystem->enabled) != MD_SS_ENABLED) { + le32_to_cpu(subsystem->enabled) != MINIDUMP_SS_ENABLED) { return rproc_coredump(rproc); } - if (le32_to_cpu(subsystem->encryption_status) != MD_SS_ENCR_DONE) { + if (le32_to_cpu(subsystem->encryption_status) != MINIDUMP_SS_ENCR_DONE) { dev_err(&rproc->dev, "Minidump not ready, skipping\n"); return; } -- GitLab From b5c9ee8296a3760760c7b5d2e305f91412adc795 Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Mon, 19 Jun 2023 11:06:31 +0800 Subject: [PATCH 0237/3445] rpmsg: glink: Add check for kstrdup Add check for the return value of kstrdup() and return the error if it fails in order to avoid NULL pointer dereference. Fixes: b4f8e52b89f6 ("rpmsg: Introduce Qualcomm RPM glink driver") Signed-off-by: Jiasheng Jiang Link: https://lore.kernel.org/r/20230619030631.12361-1-jiasheng@iscas.ac.cn Signed-off-by: Bjorn Andersson --- drivers/rpmsg/qcom_glink_native.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 2db82f67e6893..e10c05ed21bbd 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -227,6 +227,10 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, channel->glink = glink; channel->name = kstrdup(name, GFP_KERNEL); + if (!channel->name) { + kfree(channel); + return ERR_PTR(-ENOMEM); + } init_completion(&channel->open_req); init_completion(&channel->open_ack); -- GitLab From ed50ac266f67829d4732c8ca61ef1953c2cc63d0 Mon Sep 17 00:00:00 2001 From: Alexey Minnekhanov Date: Wed, 21 Jun 2023 20:50:44 +0300 Subject: [PATCH 0238/3445] dt-bindings: remoteproc: qcom,msm8996-mss-pil: Add SDM660 compatible Mention sdm660-mss-pil in compatibles list. Signed-off-by: Alexey Minnekhanov Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230621175046.61521-1-alexeymin@postmarketos.org Signed-off-by: Bjorn Andersson --- .../devicetree/bindings/remoteproc/qcom,msm8996-mss-pil.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,msm8996-mss-pil.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,msm8996-mss-pil.yaml index c1ac6ca1e759d..09da5616e1e5a 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,msm8996-mss-pil.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,msm8996-mss-pil.yaml @@ -19,6 +19,7 @@ properties: enum: - qcom,msm8996-mss-pil - qcom,msm8998-mss-pil + - qcom,sdm660-mss-pil - qcom,sdm845-mss-pil reg: @@ -245,7 +246,9 @@ allOf: - if: properties: compatible: - const: qcom,msm8998-mss-pil + enum: + - qcom,msm8998-mss-pil + - qcom,sdm660-mss-pil then: properties: clocks: -- GitLab From 10b6fec2c8c99b5d1ccbcd070da1fc8e96da0046 Mon Sep 17 00:00:00 2001 From: Alexey Minnekhanov Date: Wed, 21 Jun 2023 20:50:45 +0300 Subject: [PATCH 0239/3445] remoteproc: qcom: q6v5-mss: Add support for SDM630/636/660 Snapdragon 630/660 modem subsystem is similar to one in MSM8998 and can almost reuse it's reset sequence. Downstream sources call this q6v5 version "qdsp6v62-1-5" and its code path has additional checks for QDSP6v55_BHS_EN_REST_ACK status [2]. Inspiration is taken from Konrad Dybcio's work in [1], but reworked to use common code path with MSM8996/8998, instead of completely separate "if" block for SDM660. [1] https://github.com/SoMainline/linux/commit/7dd6dd9b936dc8d6c1f1abe299e5b065c33741e8 [2] https://github.com/MiCode/Xiaomi_Kernel_OpenSource/blob/lavender-q-oss/drivers/soc/qcom/pil-q6v5.c#L393 Co-developed-by: Konrad Dybcio Signed-off-by: Konrad Dybcio Signed-off-by: Alexey Minnekhanov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230621175046.61521-2-alexeymin@postmarketos.org Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_mss.c | 51 ++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 6e333c5e65a94..22fe7b5f5236d 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -71,6 +71,7 @@ #define QDSP6SS_MEM_PWR_CTL 0x0B0 #define QDSP6V6SS_MEM_PWR_CTL 0x034 #define QDSP6SS_STRAP_ACC 0x110 +#define QDSP6V62SS_BHS_STATUS 0x0C4 /* AXI Halt Register Offsets */ #define AXI_HALTREQ_REG 0x0 @@ -123,6 +124,7 @@ #define QDSP6v56_CLAMP_QMC_MEM BIT(22) #define QDSP6SS_XO_CBCR 0x0038 #define QDSP6SS_ACC_OVERRIDE_VAL 0x20 +#define QDSP6v55_BHS_EN_REST_ACK BIT(0) /* QDSP6v65 parameters */ #define QDSP6SS_CORE_CBCR 0x20 @@ -130,6 +132,7 @@ #define QDSP6SS_BOOT_CORE_START 0x400 #define QDSP6SS_BOOT_CMD 0x404 #define BOOT_FSM_TIMEOUT 10000 +#define BHS_CHECK_MAX_LOOPS 200 struct reg_info { struct regulator *reg; @@ -250,6 +253,7 @@ enum { MSS_MSM8998, MSS_SC7180, MSS_SC7280, + MSS_SDM660, MSS_SDM845, }; @@ -700,7 +704,8 @@ static int q6v5proc_reset(struct q6v5 *qproc) } else if (qproc->version == MSS_MSM8909 || qproc->version == MSS_MSM8953 || qproc->version == MSS_MSM8996 || - qproc->version == MSS_MSM8998) { + qproc->version == MSS_MSM8998 || + qproc->version == MSS_SDM660) { if (qproc->version != MSS_MSM8909 && qproc->version != MSS_MSM8953) @@ -734,6 +739,16 @@ static int q6v5proc_reset(struct q6v5 *qproc) val |= readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG); udelay(1); + if (qproc->version == MSS_SDM660) { + ret = readl_relaxed_poll_timeout(qproc->reg_base + QDSP6V62SS_BHS_STATUS, + i, (i & QDSP6v55_BHS_EN_REST_ACK), + 1, BHS_CHECK_MAX_LOOPS); + if (ret == -ETIMEDOUT) { + dev_err(qproc->dev, "BHS_EN_REST_ACK not set!\n"); + return -ETIMEDOUT; + } + } + /* Put LDO in bypass mode */ val |= QDSP6v56_LDO_BYP; writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); @@ -756,7 +771,7 @@ static int q6v5proc_reset(struct q6v5 *qproc) mem_pwr_ctl = QDSP6SS_MEM_PWR_CTL; i = 19; } else { - /* MSS_MSM8998 */ + /* MSS_MSM8998, MSS_SDM660 */ mem_pwr_ctl = QDSP6V6SS_MEM_PWR_CTL; i = 28; } @@ -2199,6 +2214,37 @@ static const struct rproc_hexagon_res sc7280_mss = { .version = MSS_SC7280, }; +static const struct rproc_hexagon_res sdm660_mss = { + .hexagon_mba_image = "mba.mbn", + .proxy_clk_names = (char*[]){ + "xo", + "qdss", + "mem", + NULL + }, + .active_clk_names = (char*[]){ + "iface", + "bus", + "gpll0_mss", + "mnoc_axi", + "snoc_axi", + NULL + }, + .proxy_pd_names = (char*[]){ + "cx", + "mx", + NULL + }, + .need_mem_protection = true, + .has_alt_reset = false, + .has_mba_logs = false, + .has_spare_reg = false, + .has_qaccept_regs = false, + .has_ext_cntl_regs = false, + .has_vq6 = false, + .version = MSS_SDM660, +}; + static const struct rproc_hexagon_res sdm845_mss = { .hexagon_mba_image = "mba.mbn", .proxy_clk_names = (char*[]){ @@ -2481,6 +2527,7 @@ static const struct of_device_id q6v5_of_match[] = { { .compatible = "qcom,msm8998-mss-pil", .data = &msm8998_mss}, { .compatible = "qcom,sc7180-mss-pil", .data = &sc7180_mss}, { .compatible = "qcom,sc7280-mss-pil", .data = &sc7280_mss}, + { .compatible = "qcom,sdm660-mss-pil", .data = &sdm660_mss}, { .compatible = "qcom,sdm845-mss-pil", .data = &sdm845_mss}, { }, }; -- GitLab From ba3125b47016cdc66454cf720f899b3bf806debc Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Thu, 30 Mar 2023 18:46:33 +0200 Subject: [PATCH 0240/3445] remoteproc: qcom: pas: add SDM845 SLPI compatible Add a compatible for the SDM845 SLPI to the Qualcomm remoteproc q6v5_pas driver. The SLPI is the same as in SM8150, SM8250, SM8350, and SM8450, so use the same resource in the driver. Signed-off-by: Dylan Van Assche Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230330164633.117335-4-me@dylanvanassche.be Signed-off-by: Bjorn Andersson --- drivers/remoteproc/qcom_q6v5_pas.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 8d5fb9178e304..b5447dd2dd35e 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -1172,6 +1172,7 @@ static const struct of_device_id adsp_of_match[] = { { .compatible = "qcom,sdm660-adsp-pas", .data = &adsp_resource_init}, { .compatible = "qcom,sdm845-adsp-pas", .data = &sdm845_adsp_resource_init}, { .compatible = "qcom,sdm845-cdsp-pas", .data = &sdm845_cdsp_resource_init}, + { .compatible = "qcom,sdm845-slpi-pas", .data = &sdm845_slpi_resource_init}, { .compatible = "qcom,sdx55-mpss-pas", .data = &sdx55_mpss_resource}, { .compatible = "qcom,sm6115-adsp-pas", .data = &adsp_resource_init}, { .compatible = "qcom,sm6115-cdsp-pas", .data = &cdsp_resource_init}, -- GitLab From 0e9a2a228a1ac80053d9817a8af68abcd754675e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Jul 2023 11:40:23 -0600 Subject: [PATCH 0241/3445] microblaze: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230714174023.4039938-1-robh@kernel.org Signed-off-by: Michal Simek --- arch/microblaze/kernel/reset.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/microblaze/kernel/reset.c b/arch/microblaze/kernel/reset.c index 5f4722908164d..2f66c7963084d 100644 --- a/arch/microblaze/kernel/reset.c +++ b/arch/microblaze/kernel/reset.c @@ -9,7 +9,6 @@ #include #include -#include #include void machine_shutdown(void) -- GitLab From 7559e7572c03e433efec7734af6a674fdd83dd68 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Jul 2023 11:48:35 -0600 Subject: [PATCH 0242/3445] phy: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Acked-by: Marc Kleine-Budde # for drivers/phy/phy-can-transceiver.c Acked-by: Heiko Stuebner Acked-by: Sergio Paracuellos Link: https://lore.kernel.org/r/20230714174841.4061919-1-robh@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/allwinner/phy-sun4i-usb.c | 2 -- drivers/phy/allwinner/phy-sun50i-usb3.c | 1 + drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c | 2 +- drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c | 1 + drivers/phy/amlogic/phy-meson-axg-pcie.c | 1 + drivers/phy/amlogic/phy-meson-g12a-mipi-dphy-analog.c | 1 + drivers/phy/amlogic/phy-meson-g12a-usb2.c | 2 +- drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c | 2 +- drivers/phy/amlogic/phy-meson-gxl-usb2.c | 2 +- drivers/phy/amlogic/phy-meson8-hdmi-tx.c | 2 +- drivers/phy/amlogic/phy-meson8b-usb2.c | 2 +- drivers/phy/broadcom/phy-bcm63xx-usbh.c | 1 + drivers/phy/broadcom/phy-brcm-usb.c | 1 - drivers/phy/cadence/cdns-dphy-rx.c | 1 + drivers/phy/cadence/cdns-dphy.c | 3 +-- drivers/phy/cadence/phy-cadence-torrent.c | 2 -- drivers/phy/freescale/phy-fsl-imx8m-pcie.c | 2 +- drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 2 +- drivers/phy/freescale/phy-fsl-lynx-28g.c | 1 + drivers/phy/hisilicon/phy-hi3660-usb3.c | 1 + drivers/phy/hisilicon/phy-hi3670-usb3.c | 1 + drivers/phy/hisilicon/phy-hi6220-usb.c | 1 + drivers/phy/hisilicon/phy-hisi-inno-usb2.c | 3 ++- drivers/phy/hisilicon/phy-histb-combphy.c | 3 ++- drivers/phy/hisilicon/phy-hix5hd2-sata.c | 1 + drivers/phy/ingenic/phy-ingenic-usb.c | 1 + drivers/phy/lantiq/phy-lantiq-rcu-usb2.c | 1 - drivers/phy/marvell/phy-armada38x-comphy.c | 1 + drivers/phy/marvell/phy-berlin-sata.c | 1 + drivers/phy/marvell/phy-mmp3-hsic.c | 1 + drivers/phy/marvell/phy-mmp3-usb.c | 1 + drivers/phy/marvell/phy-mvebu-a3700-comphy.c | 1 + drivers/phy/marvell/phy-mvebu-a3700-utmi.c | 2 +- drivers/phy/marvell/phy-mvebu-cp110-comphy.c | 1 + drivers/phy/marvell/phy-mvebu-cp110-utmi.c | 2 +- drivers/phy/marvell/phy-mvebu-sata.c | 1 + drivers/phy/marvell/phy-pxa-28nm-usb2.c | 1 - drivers/phy/mediatek/phy-mtk-hdmi.h | 1 - drivers/phy/mediatek/phy-mtk-mipi-dsi.h | 1 - drivers/phy/mediatek/phy-mtk-pcie.c | 2 +- drivers/phy/mediatek/phy-mtk-tphy.c | 2 +- drivers/phy/mediatek/phy-mtk-ufs.c | 1 + drivers/phy/phy-can-transceiver.c | 1 + drivers/phy/phy-xgene.c | 1 + drivers/phy/qualcomm/phy-ath79-usb.c | 1 + drivers/phy/qualcomm/phy-qcom-edp.c | 2 -- drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c | 1 - drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c | 3 +-- drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c | 2 +- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 1 - drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c | 1 - drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 1 - drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 1 - drivers/phy/qualcomm/phy-qcom-qmp-usb.c | 1 - drivers/phy/qualcomm/phy-qcom-qusb2.c | 1 - drivers/phy/qualcomm/phy-qcom-snps-eusb2.c | 1 + drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c | 1 - drivers/phy/qualcomm/phy-qcom-usb-hs.c | 2 +- drivers/phy/ralink/phy-mt7621-pci.c | 3 +-- drivers/phy/renesas/phy-rcar-gen2.c | 1 - drivers/phy/renesas/phy-rcar-gen3-pcie.c | 1 - drivers/phy/renesas/phy-rcar-gen3-usb2.c | 2 -- drivers/phy/renesas/r8a779f0-ether-serdes.c | 1 + drivers/phy/rockchip/phy-rockchip-dphy-rx0.c | 1 - drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c | 2 +- drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 1 - drivers/phy/rockchip/phy-rockchip-naneng-combphy.c | 3 ++- drivers/phy/rockchip/phy-rockchip-snps-pcie3.c | 3 ++- drivers/phy/samsung/phy-exynos-dp-video.c | 2 -- drivers/phy/samsung/phy-exynos-mipi-video.c | 3 +-- drivers/phy/samsung/phy-exynos5-usbdrd.c | 2 -- drivers/phy/samsung/phy-samsung-usb2.c | 2 -- drivers/phy/socionext/phy-uniphier-pcie.c | 2 +- drivers/phy/st/phy-spear1310-miphy.c | 3 ++- drivers/phy/st/phy-spear1340-miphy.c | 3 ++- drivers/phy/st/phy-stm32-usbphyc.c | 3 ++- drivers/phy/sunplus/phy-sunplus-usb2.c | 2 +- drivers/phy/tegra/phy-tegra194-p2u.c | 2 +- drivers/phy/tegra/xusb.c | 3 ++- drivers/phy/ti/phy-tusb1210.c | 1 + drivers/phy/ti/phy-twl4030-usb.c | 1 + 81 files changed, 65 insertions(+), 65 deletions(-) diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c index 56d53f78d0022..ec551464dd4f3 100644 --- a/drivers/phy/allwinner/phy-sun4i-usb.c +++ b/drivers/phy/allwinner/phy-sun4i-usb.c @@ -23,8 +23,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/drivers/phy/allwinner/phy-sun50i-usb3.c b/drivers/phy/allwinner/phy-sun50i-usb3.c index 84055b720016e..363f9a0df503b 100644 --- a/drivers/phy/allwinner/phy-sun50i-usb3.c +++ b/drivers/phy/allwinner/phy-sun50i-usb3.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c b/drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c index 6e9af79e152cd..08a86962d9492 100644 --- a/drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c +++ b/drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c @@ -13,8 +13,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c b/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c index a3e1108b736d6..ae898f93f97b2 100644 --- a/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c +++ b/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include diff --git a/drivers/phy/amlogic/phy-meson-axg-pcie.c b/drivers/phy/amlogic/phy-meson-axg-pcie.c index 2299bab38e05d..60be5cdc600b3 100644 --- a/drivers/phy/amlogic/phy-meson-axg-pcie.c +++ b/drivers/phy/amlogic/phy-meson-axg-pcie.c @@ -4,6 +4,7 @@ * * Copyright (C) 2020 Remi Pommarel */ +#include #include #include #include diff --git a/drivers/phy/amlogic/phy-meson-g12a-mipi-dphy-analog.c b/drivers/phy/amlogic/phy-meson-g12a-mipi-dphy-analog.c index cabdddbbabfd7..46e5f7e7eb6c8 100644 --- a/drivers/phy/amlogic/phy-meson-g12a-mipi-dphy-analog.c +++ b/drivers/phy/amlogic/phy-meson-g12a-mipi-dphy-analog.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include diff --git a/drivers/phy/amlogic/phy-meson-g12a-usb2.c b/drivers/phy/amlogic/phy-meson-g12a-usb2.c index ec2555bb83d57..a628c59e5cf0a 100644 --- a/drivers/phy/amlogic/phy-meson-g12a-usb2.c +++ b/drivers/phy/amlogic/phy-meson-g12a-usb2.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c b/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c index d2a1da8d9e588..2712c4bd549d8 100644 --- a/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c +++ b/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/phy/amlogic/phy-meson-gxl-usb2.c b/drivers/phy/amlogic/phy-meson-gxl-usb2.c index db17c3448bfed..14ea89927ab14 100644 --- a/drivers/phy/amlogic/phy-meson-gxl-usb2.c +++ b/drivers/phy/amlogic/phy-meson-gxl-usb2.c @@ -8,8 +8,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/drivers/phy/amlogic/phy-meson8-hdmi-tx.c b/drivers/phy/amlogic/phy-meson8-hdmi-tx.c index f9a6572c27d87..2617f7f6c2ec5 100644 --- a/drivers/phy/amlogic/phy-meson8-hdmi-tx.c +++ b/drivers/phy/amlogic/phy-meson8-hdmi-tx.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/phy/amlogic/phy-meson8b-usb2.c b/drivers/phy/amlogic/phy-meson8b-usb2.c index dd96763911b8b..d63147c41b8c9 100644 --- a/drivers/phy/amlogic/phy-meson8b-usb2.c +++ b/drivers/phy/amlogic/phy-meson8b-usb2.c @@ -8,8 +8,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/drivers/phy/broadcom/phy-bcm63xx-usbh.c b/drivers/phy/broadcom/phy-bcm63xx-usbh.c index 6c05ba8b08bec..f8183dea774b6 100644 --- a/drivers/phy/broadcom/phy-bcm63xx-usbh.c +++ b/drivers/phy/broadcom/phy-bcm63xx-usbh.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/phy/broadcom/phy-brcm-usb.c b/drivers/phy/broadcom/phy-brcm-usb.c index a4cfb777dd836..a16f0b58eb745 100644 --- a/drivers/phy/broadcom/phy-brcm-usb.c +++ b/drivers/phy/broadcom/phy-brcm-usb.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/cadence/cdns-dphy-rx.c b/drivers/phy/cadence/cdns-dphy-rx.c index c05b043893a93..7729cf80a9bd8 100644 --- a/drivers/phy/cadence/cdns-dphy-rx.c +++ b/drivers/phy/cadence/cdns-dphy-rx.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/phy/cadence/cdns-dphy.c b/drivers/phy/cadence/cdns-dphy.c index 6e58012b6488e..dddb66de6dba1 100644 --- a/drivers/phy/cadence/cdns-dphy.c +++ b/drivers/phy/cadence/cdns-dphy.c @@ -9,8 +9,7 @@ #include #include #include -#include -#include +#include #include #include diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index 4795b440fb776..a75c96385c57a 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -17,8 +17,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c index d4c92498ad1e3..b700f52b7b679 100644 --- a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c +++ b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c index 88826ceb72f8d..e1d7694026963 100644 --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index 569f12af2aafa..4f036c77284e1 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -2,6 +2,7 @@ /* Copyright (c) 2021-2022 NXP. */ #include +#include #include #include #include diff --git a/drivers/phy/hisilicon/phy-hi3660-usb3.c b/drivers/phy/hisilicon/phy-hi3660-usb3.c index 84adce9b42770..e2a09d67faed9 100644 --- a/drivers/phy/hisilicon/phy-hi3660-usb3.c +++ b/drivers/phy/hisilicon/phy-hi3660-usb3.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/phy/hisilicon/phy-hi3670-usb3.c b/drivers/phy/hisilicon/phy-hi3670-usb3.c index b9ffe08abaab4..40d3cf128b440 100644 --- a/drivers/phy/hisilicon/phy-hi3670-usb3.c +++ b/drivers/phy/hisilicon/phy-hi3670-usb3.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/phy/hisilicon/phy-hi6220-usb.c b/drivers/phy/hisilicon/phy-hi6220-usb.c index e92ba78da4c83..97bd363dfe877 100644 --- a/drivers/phy/hisilicon/phy-hi6220-usb.c +++ b/drivers/phy/hisilicon/phy-hi6220-usb.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include diff --git a/drivers/phy/hisilicon/phy-hisi-inno-usb2.c b/drivers/phy/hisilicon/phy-hisi-inno-usb2.c index 15dafe359552c..498afd81696bd 100644 --- a/drivers/phy/hisilicon/phy-hisi-inno-usb2.c +++ b/drivers/phy/hisilicon/phy-hisi-inno-usb2.c @@ -9,8 +9,9 @@ #include #include #include -#include +#include #include +#include #include #define INNO_PHY_PORT_NUM 2 diff --git a/drivers/phy/hisilicon/phy-histb-combphy.c b/drivers/phy/hisilicon/phy-histb-combphy.c index f1cb3e4d2add5..c44588fd5a53e 100644 --- a/drivers/phy/hisilicon/phy-histb-combphy.c +++ b/drivers/phy/hisilicon/phy-histb-combphy.c @@ -13,8 +13,9 @@ #include #include #include -#include +#include #include +#include #include #include #include diff --git a/drivers/phy/hisilicon/phy-hix5hd2-sata.c b/drivers/phy/hisilicon/phy-hix5hd2-sata.c index b0f99a9ac8577..1b26ddb4c8a71 100644 --- a/drivers/phy/hisilicon/phy-hix5hd2-sata.c +++ b/drivers/phy/hisilicon/phy-hix5hd2-sata.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/phy/ingenic/phy-ingenic-usb.c b/drivers/phy/ingenic/phy-ingenic-usb.c index 28c28d8164849..eb2721f72a4c1 100644 --- a/drivers/phy/ingenic/phy-ingenic-usb.c +++ b/drivers/phy/ingenic/phy-ingenic-usb.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c b/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c index 29d246ea24b47..82f1ffc0b0ad9 100644 --- a/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c +++ b/drivers/phy/lantiq/phy-lantiq-rcu-usb2.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/marvell/phy-armada38x-comphy.c b/drivers/phy/marvell/phy-armada38x-comphy.c index 0fe4089643342..b7d99861526a5 100644 --- a/drivers/phy/marvell/phy-armada38x-comphy.c +++ b/drivers/phy/marvell/phy-armada38x-comphy.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/phy/marvell/phy-berlin-sata.c b/drivers/phy/marvell/phy-berlin-sata.c index d70ba9bc42d9b..f972d78372eaf 100644 --- a/drivers/phy/marvell/phy-berlin-sata.c +++ b/drivers/phy/marvell/phy-berlin-sata.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include diff --git a/drivers/phy/marvell/phy-mmp3-hsic.c b/drivers/phy/marvell/phy-mmp3-hsic.c index f2537fdcc3ab4..271f1a2258efb 100644 --- a/drivers/phy/marvell/phy-mmp3-hsic.c +++ b/drivers/phy/marvell/phy-mmp3-hsic.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include diff --git a/drivers/phy/marvell/phy-mmp3-usb.c b/drivers/phy/marvell/phy-mmp3-usb.c index 04c0bada35194..5b71deb088513 100644 --- a/drivers/phy/marvell/phy-mmp3-usb.c +++ b/drivers/phy/marvell/phy-mmp3-usb.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include diff --git a/drivers/phy/marvell/phy-mvebu-a3700-comphy.c b/drivers/phy/marvell/phy-mvebu-a3700-comphy.c index d641b345afa35..24c3371e2bb29 100644 --- a/drivers/phy/marvell/phy-mvebu-a3700-comphy.c +++ b/drivers/phy/marvell/phy-mvebu-a3700-comphy.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/phy/marvell/phy-mvebu-a3700-utmi.c b/drivers/phy/marvell/phy-mvebu-a3700-utmi.c index 8834436bc9dbc..04f4fb4bed702 100644 --- a/drivers/phy/marvell/phy-mvebu-a3700-utmi.c +++ b/drivers/phy/marvell/phy-mvebu-a3700-utmi.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/phy/marvell/phy-mvebu-cp110-comphy.c b/drivers/phy/marvell/phy-mvebu-cp110-comphy.c index ddaddb3c498fd..b0dd133665986 100644 --- a/drivers/phy/marvell/phy-mvebu-cp110-comphy.c +++ b/drivers/phy/marvell/phy-mvebu-cp110-comphy.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/phy/marvell/phy-mvebu-cp110-utmi.c b/drivers/phy/marvell/phy-mvebu-cp110-utmi.c index aa27c79946104..4922a5f3327d5 100644 --- a/drivers/phy/marvell/phy-mvebu-cp110-utmi.c +++ b/drivers/phy/marvell/phy-mvebu-cp110-utmi.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/phy/marvell/phy-mvebu-sata.c b/drivers/phy/marvell/phy-mvebu-sata.c index 51a4646e29335..89a5a2b69d80f 100644 --- a/drivers/phy/marvell/phy-mvebu-sata.c +++ b/drivers/phy/marvell/phy-mvebu-sata.c @@ -10,6 +10,7 @@ #include #include #include +#include #include struct priv { diff --git a/drivers/phy/marvell/phy-pxa-28nm-usb2.c b/drivers/phy/marvell/phy-pxa-28nm-usb2.c index 1b2107f80f3a7..64afb82cf70e5 100644 --- a/drivers/phy/marvell/phy-pxa-28nm-usb2.c +++ b/drivers/phy/marvell/phy-pxa-28nm-usb2.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/mediatek/phy-mtk-hdmi.h b/drivers/phy/mediatek/phy-mtk-hdmi.h index fc2ad6a0527f3..71c02d0434857 100644 --- a/drivers/phy/mediatek/phy-mtk-hdmi.h +++ b/drivers/phy/mediatek/phy-mtk-hdmi.h @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi.h b/drivers/phy/mediatek/phy-mtk-mipi-dsi.h index 0250c4a454e7b..5d4876f1dc950 100644 --- a/drivers/phy/mediatek/phy-mtk-mipi-dsi.h +++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi.h @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/mediatek/phy-mtk-pcie.c b/drivers/phy/mediatek/phy-mtk-pcie.c index 25dbd6e357222..a2f69d6c72f08 100644 --- a/drivers/phy/mediatek/phy-mtk-pcie.c +++ b/drivers/phy/mediatek/phy-mtk-pcie.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c index 0d110e50bbfd0..05eab9014132f 100644 --- a/drivers/phy/mediatek/phy-mtk-tphy.c +++ b/drivers/phy/mediatek/phy-mtk-tphy.c @@ -13,8 +13,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/drivers/phy/mediatek/phy-mtk-ufs.c b/drivers/phy/mediatek/phy-mtk-ufs.c index fc19e0fa8ed55..0cb5a25b1b7ad 100644 --- a/drivers/phy/mediatek/phy-mtk-ufs.c +++ b/drivers/phy/mediatek/phy-mtk-ufs.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c index 5487b9dd1ead1..840b7f8a31c5f 100644 --- a/drivers/phy/phy-can-transceiver.c +++ b/drivers/phy/phy-can-transceiver.c @@ -5,6 +5,7 @@ * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com * */ +#include #include #include #include diff --git a/drivers/phy/phy-xgene.c b/drivers/phy/phy-xgene.c index d0f4546648f05..1f0f908323f0e 100644 --- a/drivers/phy/phy-xgene.c +++ b/drivers/phy/phy-xgene.c @@ -39,6 +39,7 @@ * Currently, this driver only supports Gen3 SATA mode with external clock. */ #include +#include #include #include #include diff --git a/drivers/phy/qualcomm/phy-ath79-usb.c b/drivers/phy/qualcomm/phy-ath79-usb.c index 09a77e556eceb..f8d0199c6e78f 100644 --- a/drivers/phy/qualcomm/phy-ath79-usb.c +++ b/drivers/phy/qualcomm/phy-ath79-usb.c @@ -5,6 +5,7 @@ * Copyright (C) 2015-2018 Alban Bedel */ +#include #include #include #include diff --git a/drivers/phy/qualcomm/phy-qcom-edp.c b/drivers/phy/qualcomm/phy-qcom-edp.c index fc8ca0f3018df..e0e722b9be318 100644 --- a/drivers/phy/qualcomm/phy-qcom-edp.c +++ b/drivers/phy/qualcomm/phy-qcom-edp.c @@ -13,8 +13,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c index 90f8543ba265b..52c275fbb2a1c 100644 --- a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c +++ b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c @@ -8,7 +8,6 @@ #include #include #include -#include #include /* eUSB2 status registers */ diff --git a/drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c b/drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c index d3e7d5e1d1b6a..da6f290af7221 100644 --- a/drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c +++ b/drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c @@ -13,8 +13,7 @@ #include #include #include -#include -#include +#include #include #include #include diff --git a/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c b/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c index 7bacc527fbad6..06392ed7c91b5 100644 --- a/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c +++ b/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index 36eb516f91703..e373b6b1ee996 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c index 0c603bc06e099..ab61a9c73b189 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index df505279edfde..a3bff4b71ffd8 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index d99dc1043f74e..03cd47faf3fdd 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c index f8c598dbf4674..0130bb8e809af 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c index bec6e40d5280f..c52655a383cef 100644 --- a/drivers/phy/qualcomm/phy-qcom-qusb2.c +++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/qualcomm/phy-qcom-snps-eusb2.c b/drivers/phy/qualcomm/phy-qcom-snps-eusb2.c index eeaa1eb0e24be..1484691a41d59 100644 --- a/drivers/phy/qualcomm/phy-qcom-snps-eusb2.c +++ b/drivers/phy/qualcomm/phy-qcom-snps-eusb2.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c b/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c index 6c237f3cc66db..a7af77536d4ae 100644 --- a/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c +++ b/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/qualcomm/phy-qcom-usb-hs.c b/drivers/phy/qualcomm/phy-qcom-usb-hs.c index 53e46c220a3aa..98a18987f1bec 100644 --- a/drivers/phy/qualcomm/phy-qcom-usb-hs.c +++ b/drivers/phy/qualcomm/phy-qcom-usb-hs.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/phy/ralink/phy-mt7621-pci.c b/drivers/phy/ralink/phy-mt7621-pci.c index 85888ab2d307a..2f876f158e1df 100644 --- a/drivers/phy/ralink/phy-mt7621-pci.c +++ b/drivers/phy/ralink/phy-mt7621-pci.c @@ -9,8 +9,7 @@ #include #include #include -#include -#include +#include #include #include #include diff --git a/drivers/phy/renesas/phy-rcar-gen2.c b/drivers/phy/renesas/phy-rcar-gen2.c index c375a4676a3dc..507435af26567 100644 --- a/drivers/phy/renesas/phy-rcar-gen2.c +++ b/drivers/phy/renesas/phy-rcar-gen2.c @@ -16,7 +16,6 @@ #include #include #include -#include #define USBHS_LPSTS 0x02 #define USBHS_UGCTRL 0x80 diff --git a/drivers/phy/renesas/phy-rcar-gen3-pcie.c b/drivers/phy/renesas/phy-rcar-gen3-pcie.c index 9cf786a7daac6..0ce7e9c944447 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-pcie.c +++ b/drivers/phy/renesas/phy-rcar-gen3-pcie.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index d4e2ee7e4efb1..e53eace7c91e3 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -15,8 +15,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/drivers/phy/renesas/r8a779f0-ether-serdes.c b/drivers/phy/renesas/r8a779f0-ether-serdes.c index 67f4c6f8ff91b..683b19bc411a8 100644 --- a/drivers/phy/renesas/r8a779f0-ether-serdes.c +++ b/drivers/phy/renesas/r8a779f0-ether-serdes.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/phy/rockchip/phy-rockchip-dphy-rx0.c b/drivers/phy/rockchip/phy-rockchip-dphy-rx0.c index 639452f47869c..e6a768bbb9b31 100644 --- a/drivers/phy/rockchip/phy-rockchip-dphy-rx0.c +++ b/drivers/phy/rockchip/phy-rockchip-dphy-rx0.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c index 401b0aabb1592..c879ec69bfd65 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c index 88ddbfb90eedc..053bd62e31ba7 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c index 7b8b001e4f9e3..5de5e2e97ffa0 100644 --- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c +++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c @@ -8,8 +8,9 @@ #include #include #include -#include +#include #include +#include #include #include #include diff --git a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c index 1d355b32ba559..121e5961ce114 100644 --- a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c +++ b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c @@ -12,9 +12,10 @@ #include #include #include -#include +#include #include #include +#include #include #include diff --git a/drivers/phy/samsung/phy-exynos-dp-video.c b/drivers/phy/samsung/phy-exynos-dp-video.c index 6069fedbd8f3b..a636dee075858 100644 --- a/drivers/phy/samsung/phy-exynos-dp-video.c +++ b/drivers/phy/samsung/phy-exynos-dp-video.c @@ -12,8 +12,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/drivers/phy/samsung/phy-exynos-mipi-video.c b/drivers/phy/samsung/phy-exynos-mipi-video.c index a7f67857e5b25..592d8067e848e 100644 --- a/drivers/phy/samsung/phy-exynos-mipi-video.c +++ b/drivers/phy/samsung/phy-exynos-mipi-video.c @@ -11,9 +11,8 @@ #include #include #include -#include -#include #include +#include #include #include #include diff --git a/drivers/phy/samsung/phy-exynos5-usbdrd.c b/drivers/phy/samsung/phy-exynos5-usbdrd.c index ee0848fe84324..06484abb57058 100644 --- a/drivers/phy/samsung/phy-exynos5-usbdrd.c +++ b/drivers/phy/samsung/phy-exynos5-usbdrd.c @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/drivers/phy/samsung/phy-samsung-usb2.c b/drivers/phy/samsung/phy-samsung-usb2.c index ec2befabeea6b..68a174eca0ba8 100644 --- a/drivers/phy/samsung/phy-samsung-usb2.c +++ b/drivers/phy/samsung/phy-samsung-usb2.c @@ -10,8 +10,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/drivers/phy/socionext/phy-uniphier-pcie.c b/drivers/phy/socionext/phy-uniphier-pcie.c index ebca296ef1238..c19173492b794 100644 --- a/drivers/phy/socionext/phy-uniphier-pcie.c +++ b/drivers/phy/socionext/phy-uniphier-pcie.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/phy/st/phy-spear1310-miphy.c b/drivers/phy/st/phy-spear1310-miphy.c index 292413db7da47..35a9831b51610 100644 --- a/drivers/phy/st/phy-spear1310-miphy.c +++ b/drivers/phy/st/phy-spear1310-miphy.c @@ -13,8 +13,9 @@ #include #include #include -#include +#include #include +#include #include /* SPEAr1310 Registers */ diff --git a/drivers/phy/st/phy-spear1340-miphy.c b/drivers/phy/st/phy-spear1340-miphy.c index c1d9ffa5a311e..34a1cf21015f5 100644 --- a/drivers/phy/st/phy-spear1340-miphy.c +++ b/drivers/phy/st/phy-spear1340-miphy.c @@ -13,8 +13,9 @@ #include #include #include -#include +#include #include +#include #include /* SPEAr1340 Registers */ diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c index 0a8552628cbd2..d5e7e44000b56 100644 --- a/drivers/phy/st/phy-stm32-usbphyc.c +++ b/drivers/phy/st/phy-stm32-usbphyc.c @@ -12,8 +12,9 @@ #include #include #include -#include +#include #include +#include #include #include diff --git a/drivers/phy/sunplus/phy-sunplus-usb2.c b/drivers/phy/sunplus/phy-sunplus-usb2.c index 56de41091d639..0efe74ac9c6af 100644 --- a/drivers/phy/sunplus/phy-sunplus-usb2.c +++ b/drivers/phy/sunplus/phy-sunplus-usb2.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/phy/tegra/phy-tegra194-p2u.c b/drivers/phy/tegra/phy-tegra194-p2u.c index 633e6b7472759..f49b417c9eb60 100644 --- a/drivers/phy/tegra/phy-tegra194-p2u.c +++ b/drivers/phy/tegra/phy-tegra194-p2u.c @@ -11,8 +11,8 @@ #include #include #include -#include #include +#include #define P2U_CONTROL_CMN 0x74 #define P2U_CONTROL_CMN_ENABLE_L2_EXIT_RATE_CHANGE BIT(13) diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c index a296b87dced18..ed30866e7647d 100644 --- a/drivers/phy/tegra/xusb.c +++ b/drivers/phy/tegra/xusb.c @@ -8,10 +8,11 @@ #include #include #include -#include +#include #include #include #include +#include #include #include #include diff --git a/drivers/phy/ti/phy-tusb1210.c b/drivers/phy/ti/phy-tusb1210.c index 669c13d6e402f..b4881cb344759 100644 --- a/drivers/phy/ti/phy-tusb1210.c +++ b/drivers/phy/ti/phy-tusb1210.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #define TUSB1211_POWER_CONTROL 0x3d diff --git a/drivers/phy/ti/phy-twl4030-usb.c b/drivers/phy/ti/phy-twl4030-usb.c index da50732625d17..6b265992d988f 100644 --- a/drivers/phy/ti/phy-twl4030-usb.c +++ b/drivers/phy/ti/phy-twl4030-usb.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include -- GitLab From 3f92da3ea4480648ebeb8a4802085908a5c64cee Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Jul 2023 11:49:46 -0600 Subject: [PATCH 0243/3445] soundwire: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230714174946.4063995-1-robh@kernel.org Signed-off-by: Vinod Koul --- drivers/soundwire/qcom.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 7970fdb27ba02..d178a0dc09182 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include -- GitLab From dbce1a7d5dce7318d8465b1e0d052ef1d2202237 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 17 Jul 2023 09:03:47 -0700 Subject: [PATCH 0244/3445] Input: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230714174633.4058096-1-robh@kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/sun4i-lradc-keys.c | 3 ++- drivers/input/keyboard/tm2-touchkey.c | 1 - drivers/input/misc/gpio-vibra.c | 2 +- drivers/input/misc/iqs269a.c | 2 +- drivers/input/misc/iqs626a.c | 2 +- drivers/input/misc/iqs7222.c | 2 +- drivers/input/misc/mma8450.c | 2 +- drivers/input/misc/pm8941-pwrkey.c | 1 - drivers/input/misc/pm8xxx-vibrator.c | 1 - drivers/input/misc/pmic8xxx-pwrkey.c | 1 - drivers/input/misc/pwm-vibra.c | 2 +- drivers/input/misc/sparcspkr.c | 3 ++- drivers/input/serio/apbps2.c | 2 +- drivers/input/serio/i8042-sparcio.h | 4 +++- drivers/input/serio/xilinx_ps2.c | 4 ++-- drivers/input/touchscreen/cyttsp5.c | 2 +- drivers/input/touchscreen/ili210x.c | 2 +- drivers/input/touchscreen/iqs5xx.c | 2 +- drivers/input/touchscreen/mms114.c | 1 - drivers/input/touchscreen/pixcir_i2c_ts.c | 2 +- drivers/input/touchscreen/ti_am335x_tsc.c | 1 - 21 files changed, 20 insertions(+), 22 deletions(-) diff --git a/drivers/input/keyboard/sun4i-lradc-keys.c b/drivers/input/keyboard/sun4i-lradc-keys.c index 95d927cc8b7e8..f304cab0ebdb8 100644 --- a/drivers/input/keyboard/sun4i-lradc-keys.c +++ b/drivers/input/keyboard/sun4i-lradc-keys.c @@ -21,10 +21,11 @@ #include #include #include -#include +#include #include #include #include +#include #include #include #include diff --git a/drivers/input/keyboard/tm2-touchkey.c b/drivers/input/keyboard/tm2-touchkey.c index 75bd3ea511949..0fd761ae052f1 100644 --- a/drivers/input/keyboard/tm2-touchkey.c +++ b/drivers/input/keyboard/tm2-touchkey.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include diff --git a/drivers/input/misc/gpio-vibra.c b/drivers/input/misc/gpio-vibra.c index c1c3ba5960ddf..ad44b4d18a2a1 100644 --- a/drivers/input/misc/gpio-vibra.c +++ b/drivers/input/misc/gpio-vibra.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/input/misc/iqs269a.c b/drivers/input/misc/iqs269a.c index 1272ef7b57949..c0a0856398705 100644 --- a/drivers/input/misc/iqs269a.c +++ b/drivers/input/misc/iqs269a.c @@ -17,9 +17,9 @@ #include #include #include +#include #include #include -#include #include #include #include diff --git a/drivers/input/misc/iqs626a.c b/drivers/input/misc/iqs626a.c index 50035c25c3f70..0dab54d3a0603 100644 --- a/drivers/input/misc/iqs626a.c +++ b/drivers/input/misc/iqs626a.c @@ -19,8 +19,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/drivers/input/misc/iqs7222.c b/drivers/input/misc/iqs7222.c index a9c1dba1e8c1d..36aeeae776110 100644 --- a/drivers/input/misc/iqs7222.c +++ b/drivers/input/misc/iqs7222.c @@ -16,8 +16,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/drivers/input/misc/mma8450.c b/drivers/input/misc/mma8450.c index 76a190b2220bd..662b436d765bb 100644 --- a/drivers/input/misc/mma8450.c +++ b/drivers/input/misc/mma8450.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #define MMA8450_DRV_NAME "mma8450" diff --git a/drivers/input/misc/pm8941-pwrkey.c b/drivers/input/misc/pm8941-pwrkey.c index 74d77d8aaeff2..ba747c5b2b5fc 100644 --- a/drivers/input/misc/pm8941-pwrkey.c +++ b/drivers/input/misc/pm8941-pwrkey.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c index 04cb87efd7991..5c288fe7accf1 100644 --- a/drivers/input/misc/pm8xxx-vibrator.c +++ b/drivers/input/misc/pm8xxx-vibrator.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c index 89fb137e37157..c406a1cca5c44 100644 --- a/drivers/input/misc/pmic8xxx-pwrkey.c +++ b/drivers/input/misc/pmic8xxx-pwrkey.c @@ -12,7 +12,6 @@ #include #include #include -#include #define PON_CNTL_1 0x1C #define PON_CNTL_PULL_UP BIT(7) diff --git a/drivers/input/misc/pwm-vibra.c b/drivers/input/misc/pwm-vibra.c index a3cde30ee8d2b..acac79c488aa1 100644 --- a/drivers/input/misc/pwm-vibra.c +++ b/drivers/input/misc/pwm-vibra.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index cdcb7737c46aa..e5dd84725c6e7 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -9,7 +9,8 @@ #include #include #include -#include +#include +#include #include #include diff --git a/drivers/input/serio/apbps2.c b/drivers/input/serio/apbps2.c index 513d96e40e0ef..3f6866d39b862 100644 --- a/drivers/input/serio/apbps2.c +++ b/drivers/input/serio/apbps2.c @@ -14,11 +14,11 @@ * Contributors: Daniel Hellstrom */ #include -#include #include #include #include #include +#include #include #include #include diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h index c712c1fe06053..b68793bf05c8c 100644 --- a/drivers/input/serio/i8042-sparcio.h +++ b/drivers/input/serio/i8042-sparcio.h @@ -2,7 +2,9 @@ #ifndef _I8042_SPARCIO_H #define _I8042_SPARCIO_H -#include +#include +#include +#include #include #include diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index 960d7601fbc82..f3d28da70b75c 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c @@ -14,10 +14,10 @@ #include #include #include +#include #include -#include #include -#include +#include #define DRIVER_NAME "xilinx_ps2" diff --git a/drivers/input/touchscreen/cyttsp5.c b/drivers/input/touchscreen/cyttsp5.c index b461ded946fc8..db5a885ecd728 100644 --- a/drivers/input/touchscreen/cyttsp5.c +++ b/drivers/input/touchscreen/cyttsp5.c @@ -18,8 +18,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index f7cd773f7292a..ad6828e4f2e2d 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -8,8 +8,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index 0aa9d6492df8f..b4768b66eb101 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -23,8 +23,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index ac12494c7930d..6109cf7e779a2 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 0b4576091dacc..4ede0687beb09 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -13,8 +13,8 @@ #include #include #include -#include #include +#include #include #define PIXCIR_MAX_SLOTS 5 /* Max fingers supported by driver */ diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index decf2d24a1155..9aa4e35fb4f5a 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include -- GitLab From 904ef2c47d8f3d0f0c7d5c0dd68ecc95908d7360 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 17 Jul 2023 08:50:36 -0700 Subject: [PATCH 0245/3445] Input: gpio-keys - convert to dev_err_probe() Use the dev_err_probe() helper, instead of open-coding the same operation. While at it, invert the error checking logic to simplify code flow. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/d225a837c50e2b19a41555a8f7ce0f94b1689aa4.1689600353.git.geert+renesas@glider.be Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index c928829a8b0ce..2e7c2c046e675 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -523,18 +523,15 @@ static int gpio_keys_setup_key(struct platform_device *pdev, NULL, GPIOD_IN, desc); if (IS_ERR(bdata->gpiod)) { error = PTR_ERR(bdata->gpiod); - if (error == -ENOENT) { - /* - * GPIO is optional, we may be dealing with - * purely interrupt-driven setup. - */ - bdata->gpiod = NULL; - } else { - if (error != -EPROBE_DEFER) - dev_err(dev, "failed to get gpio: %d\n", - error); - return error; - } + if (error != -ENOENT) + return dev_err_probe(dev, error, + "failed to get gpio\n"); + + /* + * GPIO is optional, we may be dealing with + * purely interrupt-driven setup. + */ + bdata->gpiod = NULL; } } else if (gpio_is_valid(button->gpio)) { /* -- GitLab From fcbb485d9f720b176d7bac0802181901eedddbed Mon Sep 17 00:00:00 2001 From: Miaohe Lin Date: Sat, 15 Jul 2023 11:08:29 +0800 Subject: [PATCH 0246/3445] cgroup: use cached local variable parent in for loop Use local variable parent to initialize iter tcgrp in for loop so the size of cgroup.o can be reduced by 64 bytes. No functional change intended. Signed-off-by: Miaohe Lin Signed-off-by: Tejun Heo --- kernel/cgroup/cgroup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 30c9c2503ccf1..e9a62de3faf9b 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -5894,7 +5894,7 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) parent->nr_threaded_children--; spin_lock_irq(&css_set_lock); - for (tcgrp = cgroup_parent(cgrp); tcgrp; tcgrp = cgroup_parent(tcgrp)) { + for (tcgrp = parent; tcgrp; tcgrp = cgroup_parent(tcgrp)) { tcgrp->nr_descendants--; tcgrp->nr_dying_descendants++; /* -- GitLab From 6f71780e7fadf778eeb45e830d31339af53533fc Mon Sep 17 00:00:00 2001 From: Miaohe Lin Date: Mon, 17 Jul 2023 19:28:00 +0800 Subject: [PATCH 0247/3445] cgroup: fix obsolete function name cgroup_taskset_migrate() has been renamed to cgroup_migrate_execute() since commit e595cd706982 ("cgroup: track migration context in cgroup_mgctx"). Update the corresponding comment. Signed-off-by: Miaohe Lin Signed-off-by: Tejun Heo --- kernel/cgroup/cgroup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index e9a62de3faf9b..aa2cc32e60c0a 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -2477,7 +2477,7 @@ struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset, /* * This function may be called both before and - * after cgroup_taskset_migrate(). The two cases + * after cgroup_migrate_execute(). The two cases * can be distinguished by looking at whether @cset * has its ->mg_dst_cset set. */ -- GitLab From c25ff4b911a11908c7f05bc07cc6762f9cece2b5 Mon Sep 17 00:00:00 2001 From: Kamalesh Babulal Date: Mon, 17 Jul 2023 20:09:23 +0530 Subject: [PATCH 0248/3445] cgroup: remove cgrp->kn check in css_populate_dir() cgroup_create() creates cgrp and assigns the kernfs_node to cgrp->kn, then cgroup_mkdir() populates base and csses cft file by calling css_populate_dir() and cgroup_apply_control_enable() with a valid cgrp->kn. Check for NULL cgrp->kn, will always be false, remove it. Signed-off-by: Kamalesh Babulal Signed-off-by: Tejun Heo --- kernel/cgroup/cgroup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index aa2cc32e60c0a..3c1bb9ecea105 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -1714,7 +1714,7 @@ static int css_populate_dir(struct cgroup_subsys_state *css) struct cftype *cfts, *failed_cfts; int ret; - if ((css->flags & CSS_VISIBLE) || !cgrp->kn) + if (css->flags & CSS_VISIBLE) return 0; if (!css->ss) { -- GitLab From 23316be8a9d450f33a21f1efe7d89570becbec58 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Sun, 16 Jul 2023 04:28:04 +0200 Subject: [PATCH 0249/3445] hwspinlock: qcom: add missing regmap config for SFPB MMIO implementation Commit 5d4753f741d8 ("hwspinlock: qcom: add support for MMIO on older SoCs") introduced and made regmap_config mandatory in the of_data struct but didn't add the regmap_config for sfpb based devices. SFPB based devices can both use the legacy syscon way to probe or the new MMIO way and currently device that use the MMIO way are broken as they lack the definition of the now required regmap_config and always return -EINVAL (and indirectly makes fail probing everything that depends on it, smem, nandc with smem-parser...) Fix this by correctly adding the missing regmap_config and restore function of hwspinlock on SFPB based devices with MMIO implementation. Cc: stable@vger.kernel.org Fixes: 5d4753f741d8 ("hwspinlock: qcom: add support for MMIO on older SoCs") Signed-off-by: Christian Marangi Link: https://lore.kernel.org/r/20230716022804.21239-1-ansuelsmth@gmail.com Signed-off-by: Bjorn Andersson --- drivers/hwspinlock/qcom_hwspinlock.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/hwspinlock/qcom_hwspinlock.c b/drivers/hwspinlock/qcom_hwspinlock.c index dee7bb5eae382..a0fd67fd29344 100644 --- a/drivers/hwspinlock/qcom_hwspinlock.c +++ b/drivers/hwspinlock/qcom_hwspinlock.c @@ -69,9 +69,18 @@ static const struct hwspinlock_ops qcom_hwspinlock_ops = { .unlock = qcom_hwspinlock_unlock, }; +static const struct regmap_config sfpb_mutex_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x100, + .fast_io = true, +}; + static const struct qcom_hwspinlock_of_data of_sfpb_mutex = { .offset = 0x4, .stride = 0x4, + .regmap_config = &sfpb_mutex_config, }; static const struct regmap_config tcsr_msm8226_mutex_config = { -- GitLab From 7784311cad42e67a1a51a9d1b961752c0f9b7200 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Mon, 26 Jun 2023 22:00:24 +0200 Subject: [PATCH 0250/3445] dt-bindings: remoteproc: qcom,msm8996-mss-pil: Fix 8996 clocks Change RPMH to RPM (as RPMh was introduced 2 generations later) and drop the prng reference, which made ARRAY_SIZE(clocks) != ARRAY_SIZE(clock-names). Fixes: bdea142295ff ("dt-bindings: remoteproc: qcom,q6v5: Move MSM8996 to schema") Signed-off-by: Konrad Dybcio Acked-by: Rob Herring Link: https://lore.kernel.org/r/20230626-topic-bindingsfixups-v1-2-254ae8642e69@linaro.org Signed-off-by: Bjorn Andersson --- .../bindings/remoteproc/qcom,msm8996-mss-pil.yaml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,msm8996-mss-pil.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,msm8996-mss-pil.yaml index 09da5616e1e5a..0643faae2c394 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,msm8996-mss-pil.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,msm8996-mss-pil.yaml @@ -216,13 +216,12 @@ allOf: - description: GCC MSS IFACE clock - description: GCC MSS BUS clock - description: GCC MSS MEM clock - - description: RPMH XO clock + - description: RPM XO clock - description: GCC MSS GPLL0 clock - description: GCC MSS SNOC_AXI clock - description: GCC MSS MNOC_AXI clock - - description: RPMH PNOC clock - - description: GCC MSS PRNG clock - - description: RPMH QDSS clock + - description: RPM PNOC clock + - description: RPM QDSS clock clock-names: items: - const: iface -- GitLab From fd2d4e4c19864fdd400d961de899163323ab7fa9 Mon Sep 17 00:00:00 2001 From: Mrinmay Sarkar Date: Fri, 14 Jul 2023 10:38:34 +0530 Subject: [PATCH 0251/3445] dt-bindings: phy: qcom,qmp: Add sa8775p QMP PCIe PHY Add devicetree YAML binding for Qualcomm QMP PCIe PHY for SA8775p platform. Signed-off-by: Mrinmay Sarkar Link: https://lore.kernel.org/r/1689311319-22054-3-git-send-email-quic_msarkar@quicinc.com Signed-off-by: Vinod Koul --- .../phy/qcom,sc8280xp-qmp-pcie-phy.yaml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml index a0407fc795637..ca55ed9d74acc 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml @@ -16,6 +16,8 @@ description: properties: compatible: enum: + - qcom,sa8775p-qmp-gen4x2-pcie-phy + - qcom,sa8775p-qmp-gen4x4-pcie-phy - qcom,sc8280xp-qmp-gen3x1-pcie-phy - qcom,sc8280xp-qmp-gen3x2-pcie-phy - qcom,sc8280xp-qmp-gen3x4-pcie-phy @@ -30,7 +32,7 @@ properties: clocks: minItems: 5 - maxItems: 6 + maxItems: 7 clock-names: minItems: 5 @@ -41,6 +43,7 @@ properties: - const: rchng - const: pipe - const: pipediv2 + - const: phy_aux power-domains: maxItems: 1 @@ -136,6 +139,20 @@ allOf: clock-names: minItems: 6 + - if: + properties: + compatible: + contains: + enum: + - qcom,sa8775p-qmp-gen4x2-pcie-phy + - qcom,sa8775p-qmp-gen4x4-pcie-phy + then: + properties: + clocks: + minItems: 7 + clock-names: + minItems: 7 + - if: properties: compatible: -- GitLab From a05b6d5135ec3e65520ae0eaa1b24d4c6549424e Mon Sep 17 00:00:00 2001 From: Mrinmay Sarkar Date: Fri, 14 Jul 2023 10:38:36 +0530 Subject: [PATCH 0252/3445] phy: qcom-qmp-pcie: add support for sa8775p Add support for dual and four lane PHY found on sa8755p platform. Signed-off-by: Mrinmay Sarkar Link: https://lore.kernel.org/r/1689311319-22054-5-git-send-email-quic_msarkar@quicinc.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 341 ++++++++++++++++++ .../qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h | 1 + .../phy-qcom-qmp-qserdes-txrx-v5_20.h | 2 + 3 files changed, 344 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index a3bff4b71ffd8..e15ea113b2db5 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -1909,6 +1909,244 @@ static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_pcs_misc_tbl[] = { QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_G4_FOM_EQ_CONFIG5, 0xf2), }; +static const struct qmp_phy_init_tbl sa8775p_qmp_gen4x2_pcie_serdes_alt_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIAS_EN_CLKBUFLR_EN, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP_EN, 0x46), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP_CFG, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE_MAP, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_SEL, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_HS_SWITCH_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORECLK_DIV_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORECLK_DIV_MODE1, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CMN_MISC1, 0x88), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORE_CLK_EN, 0x60), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CMN_CONFIG, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CMN_MODE, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_DC_LEVEL_CTRL, 0x0f), +}; + +static const struct qmp_phy_init_tbl sa8775p_qmp_gen4x2_pcie_rc_serdes_alt_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_EN_CENTER, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_PER1, 0x31), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE1_MODE0, 0xde), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE2_MODE0, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE1_MODE1, 0x97), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE2_MODE1, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CLK_ENABLE1, 0x90), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CP_CTRL_MODE1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_CCTRL_MODE1, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_EN_SEL, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP1_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP2_MODE0, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP1_MODE1, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP2_MODE1, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DEC_START_MODE1, 0xd0), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START1_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START2_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START3_MODE0, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START1_MODE1, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START2_MODE1, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START3_MODE1, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CLK_SELECT, 0x34), +}; + +static const struct qmp_phy_init_tbl sa8775p_qmp_gen4x2_pcie_rx_alt_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_PI_CONTROLS, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B0, 0x9a), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B1, 0xb0), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B2, 0x92), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B3, 0xf0), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B4, 0x42), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B5, 0x99), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B6, 0x29), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B0, 0x9a), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B1, 0xfb), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B2, 0x92), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B3, 0xec), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B4, 0x43), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B5, 0xdd), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B6, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B0, 0xf3), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B1, 0xf8), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B2, 0xec), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B3, 0xd6), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B4, 0x83), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B5, 0xf5), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B6, 0x5e), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_PHPRE_CTRL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_AUX_DATA_THRESH_BIN_RATE_0_1, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_AUX_DATA_THRESH_BIN_RATE_2_3, 0x37), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_3, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH1_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH2_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH3_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH4_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH5_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH6_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH1_RATE210, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH2_RATE210, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH3_RATE210, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_Q_PI_INTRINSIC_BIAS_RATE32, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_FO_GAIN_RATE2, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_FO_GAIN_RATE3, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_SO_GAIN_RATE3, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_VGA_CAL_CNTRL1, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_VGA_CAL_MAN_VAL, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x7c), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_IDAC_SAOFFSET, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_DAC_ENABLE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_GM_CAL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_TX_ADAPT_POST_THRESH1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_TX_ADAPT_POST_THRESH2, 0x1f), +}; + +static const struct qmp_phy_init_tbl sa8775p_qmp_gen4_pcie_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_20_TX_RES_CODE_LANE_OFFSET_TX, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_TX_RES_CODE_LANE_OFFSET_RX, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V5_20_TX_LANE_MODE_1, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V5_20_TX_LANE_MODE_2, 0xf6), + QMP_PHY_INIT_CFG(QSERDES_V5_20_TX_LANE_MODE_3, 0x0f), +}; + +static const struct qmp_phy_init_tbl sa8775p_qmp_gen4_pcie_pcs_misc_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_EQ_CONFIG1, 0x16), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_G4_EQ_CONFIG5, 0x02), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_G4_PRE_GAIN, 0x2e), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_RX_MARGINING_CONFIG3, 0x28), +}; + +static const struct qmp_phy_init_tbl sa8775p_qmp_gen4_pcie_rc_pcs_misc_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_POWER_STATE_CONFIG2, 0x1d), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_OSC_DTCT_ACTIONS, 0x00), +}; + +static const struct qmp_phy_init_tbl sa8775p_qmp_gen4x2_pcie_pcs_alt_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_EQ_CONFIG4, 0x16), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_EQ_CONFIG5, 0x22), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_LANE1_INSIG_SW_CTRL2, 0x00), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_LANE1_INSIG_MX_CTRL2, 0x00), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_G3S2_PRE_GAIN, 0x2e), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_RX_SIGDET_LVL, 0x66), +}; + +static const struct qmp_phy_init_tbl sa8775p_qmp_gen4x4_pcie_rx_alt_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_AUX_DATA_THRESH_BIN_RATE_0_1, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_AUX_DATA_THRESH_BIN_RATE_2_3, 0x37), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_3, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_DAC_ENABLE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_GM_CAL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_PHPRE_CTRL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x7c), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_IDAC_SAOFFSET, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH1_RATE210, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH1_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH2_RATE210, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH2_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH3_RATE210, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH3_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH4_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH5_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH6_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_Q_PI_INTRINSIC_BIAS_RATE32, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B0, 0x99), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B1, 0xb0), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B2, 0x92), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B3, 0xf0), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B4, 0x42), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B5, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B6, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B0, 0x9a), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B1, 0xb6), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B2, 0x92), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B3, 0xf0), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B4, 0x43), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B5, 0xdd), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B6, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B0, 0xf3), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B1, 0xf6), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B2, 0xee), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B3, 0xd2), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B4, 0x83), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B5, 0xf9), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B6, 0x3d), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_TX_ADAPT_POST_THRESH1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_TX_ADAPT_POST_THRESH2, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_FO_GAIN_RATE2, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_FO_GAIN_RATE3, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_SO_GAIN_RATE3, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_PI_CONTROLS, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_VGA_CAL_CNTRL1, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_VGA_CAL_MAN_VAL, 0x08), +}; + +static const struct qmp_phy_init_tbl sa8775p_qmp_gen4x4_pcie_pcs_alt_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_EQ_CONFIG4, 0x16), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_EQ_CONFIG5, 0x22), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_G3S2_PRE_GAIN, 0x2e), + QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_RX_SIGDET_LVL, 0x66), +}; + +static const struct qmp_phy_init_tbl sa8775p_qmp_gen4x4_pcie_serdes_alt_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_CCTRL_MODE1, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP_EN, 0x46), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP_CFG, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE_MAP, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_SEL, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_HS_SWITCH_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORECLK_DIV_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORECLK_DIV_MODE1, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CMN_MISC1, 0x88), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORE_CLK_EN, 0x60), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CMN_CONFIG, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CMN_MODE, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_DC_LEVEL_CTRL, 0x0f), +}; + + +static const struct qmp_phy_init_tbl sa8775p_qmp_gen4x4_pcie_rc_serdes_alt_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_EN_CENTER, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_PER1, 0x31), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE1_MODE0, 0xde), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE2_MODE0, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE1_MODE1, 0x97), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE2_MODE1, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIAS_EN_CLKBUFLR_EN, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CLK_ENABLE1, 0x90), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CP_CTRL_MODE1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_EN_SEL, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP1_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP2_MODE0, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP1_MODE1, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP2_MODE1, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DEC_START_MODE1, 0xd0), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START1_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START2_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START3_MODE0, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START1_MODE1, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START2_MODE1, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_DIV_FRAC_START3_MODE1, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_CLK_SELECT, 0x34), +}; + struct qmp_pcie_offsets { u16 serdes; u16 pcs; @@ -2053,6 +2291,10 @@ static const char * const sdm845_pciephy_clk_l[] = { "aux", "cfg_ahb", "ref", "refgen", }; +static const char * const sa8775p_pciephy_clk_l[] = { + "aux", "cfg_ahb", "ref", "rchng", "phy_aux", +}; + /* list of regulators */ static const char * const qmp_phy_vreg_l[] = { "vdda-phy", "vdda-pll", @@ -2092,6 +2334,27 @@ static const struct qmp_pcie_offsets qmp_pcie_offsets_v6_20 = { .ln_shrd = 0x0e00, }; +static const struct qmp_pcie_offsets qmp_pcie_offsets_v5_20 = { + .serdes = 0x1000, + .pcs = 0x1200, + .pcs_misc = 0x1400, + .tx = 0x0000, + .rx = 0x0200, + .tx2 = 0x0800, + .rx2 = 0x0a00, + .ln_shrd = 0x0e00, +}; + +static const struct qmp_pcie_offsets qmp_pcie_offsets_v5_30 = { + .serdes = 0x2000, + .pcs = 0x2200, + .pcs_misc = 0x2400, + .tx = 0x0, + .rx = 0x0200, + .tx2 = 0x3800, + .rx2 = 0x3a00, +}; + static const struct qmp_phy_cfg ipq8074_pciephy_cfg = { .lanes = 1, @@ -2742,6 +3005,78 @@ static const struct qmp_phy_cfg sm8550_qmp_gen4x2_pciephy_cfg = { .has_nocsr_reset = true, }; +static const struct qmp_phy_cfg sa8775p_qmp_gen4x2_pciephy_cfg = { + .lanes = 2, + .offsets = &qmp_pcie_offsets_v5_20, + + .tbls = { + .serdes = sa8775p_qmp_gen4x2_pcie_serdes_alt_tbl, + .serdes_num = ARRAY_SIZE(sa8775p_qmp_gen4x2_pcie_serdes_alt_tbl), + .tx = sa8775p_qmp_gen4_pcie_tx_tbl, + .tx_num = ARRAY_SIZE(sa8775p_qmp_gen4_pcie_tx_tbl), + .rx = sa8775p_qmp_gen4x2_pcie_rx_alt_tbl, + .rx_num = ARRAY_SIZE(sa8775p_qmp_gen4x2_pcie_rx_alt_tbl), + .pcs = sa8775p_qmp_gen4x2_pcie_pcs_alt_tbl, + .pcs_num = ARRAY_SIZE(sa8775p_qmp_gen4x2_pcie_pcs_alt_tbl), + .pcs_misc = sa8775p_qmp_gen4_pcie_pcs_misc_tbl, + .pcs_misc_num = ARRAY_SIZE(sa8775p_qmp_gen4_pcie_pcs_misc_tbl), + }, + + .tbls_rc = &(const struct qmp_phy_cfg_tbls) { + .serdes = sa8775p_qmp_gen4x2_pcie_rc_serdes_alt_tbl, + .serdes_num = ARRAY_SIZE(sa8775p_qmp_gen4x2_pcie_rc_serdes_alt_tbl), + .pcs_misc = sa8775p_qmp_gen4_pcie_rc_pcs_misc_tbl, + .pcs_misc_num = ARRAY_SIZE(sa8775p_qmp_gen4_pcie_rc_pcs_misc_tbl), + }, + + .clk_list = sa8775p_pciephy_clk_l, + .num_clks = ARRAY_SIZE(sa8775p_pciephy_clk_l), + .reset_list = sdm845_pciephy_reset_l, + .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = pciephy_v5_regs_layout, + + .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, + .phy_status = PHYSTATUS_4_20, +}; + +static const struct qmp_phy_cfg sa8775p_qmp_gen4x4_pciephy_cfg = { + .lanes = 4, + .offsets = &qmp_pcie_offsets_v5_30, + + .tbls = { + .serdes = sa8775p_qmp_gen4x4_pcie_serdes_alt_tbl, + .serdes_num = ARRAY_SIZE(sa8775p_qmp_gen4x4_pcie_serdes_alt_tbl), + .tx = sa8775p_qmp_gen4_pcie_tx_tbl, + .tx_num = ARRAY_SIZE(sa8775p_qmp_gen4_pcie_tx_tbl), + .rx = sa8775p_qmp_gen4x4_pcie_rx_alt_tbl, + .rx_num = ARRAY_SIZE(sa8775p_qmp_gen4x4_pcie_rx_alt_tbl), + .pcs = sa8775p_qmp_gen4x4_pcie_pcs_alt_tbl, + .pcs_num = ARRAY_SIZE(sa8775p_qmp_gen4x4_pcie_pcs_alt_tbl), + .pcs_misc = sa8775p_qmp_gen4_pcie_pcs_misc_tbl, + .pcs_misc_num = ARRAY_SIZE(sa8775p_qmp_gen4_pcie_pcs_misc_tbl), + }, + + .tbls_rc = &(const struct qmp_phy_cfg_tbls) { + .serdes = sa8775p_qmp_gen4x4_pcie_rc_serdes_alt_tbl, + .serdes_num = ARRAY_SIZE(sa8775p_qmp_gen4x4_pcie_rc_serdes_alt_tbl), + .pcs_misc = sa8775p_qmp_gen4_pcie_rc_pcs_misc_tbl, + .pcs_misc_num = ARRAY_SIZE(sa8775p_qmp_gen4_pcie_rc_pcs_misc_tbl), + }, + + .clk_list = sa8775p_pciephy_clk_l, + .num_clks = ARRAY_SIZE(sa8775p_pciephy_clk_l), + .reset_list = sdm845_pciephy_reset_l, + .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = pciephy_v5_regs_layout, + + .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, + .phy_status = PHYSTATUS_4_20, +}; + static void qmp_pcie_configure_lane(void __iomem *base, const struct qmp_phy_init_tbl tbl[], int num, @@ -3376,6 +3711,12 @@ static const struct of_device_id qmp_pcie_of_match_table[] = { }, { .compatible = "qcom,msm8998-qmp-pcie-phy", .data = &msm8998_pciephy_cfg, + }, { + .compatible = "qcom,sa8775p-qmp-gen4x2-pcie-phy", + .data = &sa8775p_qmp_gen4x2_pciephy_cfg, + }, { + .compatible = "qcom,sa8775p-qmp-gen4x4-pcie-phy", + .data = &sa8775p_qmp_gen4x4_pciephy_cfg, }, { .compatible = "qcom,sc8180x-qmp-pcie-phy", .data = &sc8180x_pciephy_cfg, diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h index a3a056741fc77..cdf8c04ea078a 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h @@ -7,6 +7,7 @@ #define QCOM_PHY_QMP_PCS_PCIE_V5_20_H_ /* Only for QMP V5_20 PHY - PCIe PCS registers */ +#define QPHY_V5_20_PCS_PCIE_POWER_STATE_CONFIG2 0x00c #define QPHY_V5_20_PCS_PCIE_ENDPOINT_REFCLK_DRIVE 0x01c #define QPHY_V5_20_PCS_PCIE_OSC_DTCT_MODE2_CONFIG5 0x084 #define QPHY_V5_20_PCS_PCIE_OSC_DTCT_ACTIONS 0x090 diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v5_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v5_20.h index c7b12c1fb7f54..cf91154eed139 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v5_20.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v5_20.h @@ -19,6 +19,7 @@ /* Only for QMP V5_20 PHY - RX registers */ #define QSERDES_V5_20_RX_UCDR_FO_GAIN_RATE2 0x008 #define QSERDES_V5_20_RX_UCDR_FO_GAIN_RATE3 0x00c +#define QSERDES_V5_20_RX_UCDR_SO_GAIN_RATE3 0x01c #define QSERDES_V5_20_RX_UCDR_PI_CONTROLS 0x020 #define QSERDES_V5_20_RX_AUX_DATA_THRESH_BIN_RATE_0_1 0x02c #define QSERDES_V5_20_RX_AUX_DATA_THRESH_BIN_RATE_2_3 0x030 @@ -80,5 +81,6 @@ #define QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH4_RATE3 0x210 #define QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH5_RATE3 0x218 #define QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH6_RATE3 0x220 +#define QSERDES_V5_20_RX_Q_PI_INTRINSIC_BIAS_RATE32 0x238 #endif -- GitLab From f66782cff479807ad7e98f0cf6a0c0babfe0159b Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 17 Jul 2023 19:35:11 +0200 Subject: [PATCH 0253/3445] dt-bindings: phy: rockchip: add RK3588 PCIe v3 phy When the RK3568 PCIe v3 PHY supported has been upstreamed, RK3588 support was included, but the DT binding does not reflect this. This adds the missing bits. Reviewed-by: Conor Dooley Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20230717173512.65169-2-sebastian.reichel@collabora.com Signed-off-by: Vinod Koul --- .../bindings/phy/rockchip,pcie3-phy.yaml | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/rockchip,pcie3-phy.yaml b/Documentation/devicetree/bindings/phy/rockchip,pcie3-phy.yaml index 9f2d8d2cc7a54..c4fbffcde6e40 100644 --- a/Documentation/devicetree/bindings/phy/rockchip,pcie3-phy.yaml +++ b/Documentation/devicetree/bindings/phy/rockchip,pcie3-phy.yaml @@ -13,19 +13,18 @@ properties: compatible: enum: - rockchip,rk3568-pcie3-phy + - rockchip,rk3588-pcie3-phy reg: maxItems: 1 clocks: - minItems: 3 + minItems: 1 maxItems: 3 clock-names: - items: - - const: refclk_m - - const: refclk_n - - const: pclk + minItems: 1 + maxItems: 3 data-lanes: description: which lanes (by position) should be mapped to which @@ -61,6 +60,30 @@ required: - rockchip,phy-grf - "#phy-cells" +allOf: + - if: + properties: + compatible: + enum: + - rockchip,rk3588-pcie3-phy + then: + properties: + clocks: + maxItems: 1 + clock-names: + items: + - const: pclk + else: + properties: + clocks: + minItems: 3 + + clock-names: + items: + - const: refclk_m + - const: refclk_n + - const: pclk + additionalProperties: false examples: -- GitLab From 46d57a7a8e331ad402783a77d246c4196ba21863 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 3 Jul 2023 17:58:38 +0300 Subject: [PATCH 0254/3445] docs: printk-formats: Fix hex printing of signed values The commit cbacb5ab0aa0 ("docs: printk-formats: Stop encouraging use of unnecessary %h[xudi] and %hh[xudi]") obviously missed the point of sign promotion for the signed values lesser than int. In such case %x prints not the same as %h[h]x. Restore back those specifiers for the signed hex cases. Fixes: cbacb5ab0aa0 ("docs: printk-formats: Stop encouraging use of unnecessary %h[xudi] and %hh[xudi]") Signed-off-by: Andy Shevchenko Reviewed-by: Petr Mladek Signed-off-by: Petr Mladek Link: https://lore.kernel.org/r/20230703145839.14248-1-andriy.shevchenko@linux.intel.com --- Documentation/core-api/printk-formats.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst index dbe1aacc79d0f..956c87b3ba8bc 100644 --- a/Documentation/core-api/printk-formats.rst +++ b/Documentation/core-api/printk-formats.rst @@ -15,9 +15,9 @@ Integer types If variable is of Type, use printk format specifier: ------------------------------------------------------------ - char %d or %x + char %d or %hhx unsigned char %u or %x - short int %d or %x + short int %d or %hx unsigned short int %u or %x int %d or %x unsigned int %u or %x @@ -27,9 +27,9 @@ Integer types unsigned long long %llu or %llx size_t %zu or %zx ssize_t %zd or %zx - s8 %d or %x + s8 %d or %hhx u8 %u or %x - s16 %d or %x + s16 %d or %hx u16 %u or %x s32 %d or %x u32 %u or %x -- GitLab From 243e212ff82f6aaabc2793049571a199067738d3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 3 Jul 2023 17:58:39 +0300 Subject: [PATCH 0255/3445] docs: printk-formats: Treat char as always unsigned The Linux kernel switched to have char be equivalent to usigned char. Reflect this in the printk specifiers. Fixes: 3bc753c06dd0 ("kbuild: treat char as always unsigned") Signed-off-by: Andy Shevchenko Reviewed-by: Petr Mladek Signed-off-by: Petr Mladek Link: https://lore.kernel.org/r/20230703145839.14248-2-andriy.shevchenko@linux.intel.com --- Documentation/core-api/printk-formats.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst index 956c87b3ba8bc..0eed8a2dcae93 100644 --- a/Documentation/core-api/printk-formats.rst +++ b/Documentation/core-api/printk-formats.rst @@ -15,8 +15,9 @@ Integer types If variable is of Type, use printk format specifier: ------------------------------------------------------------ - char %d or %hhx + signed char %d or %hhx unsigned char %u or %x + char %u or %x short int %d or %hx unsigned short int %u or %x int %d or %x -- GitLab From d629e5bcdfd9ba1c9da6da9144cc7ba43f04a6dc Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 17 Jul 2023 09:55:38 -0700 Subject: [PATCH 0256/3445] rpmsg: glink: Avoid dereferencing NULL channel The newly introduced signal command handler checks for non-existing channel and print an error message, but then continues on to dereference that same channel. Instead abort the handler when no channel is found. Fixes: a2b73aa512a4 ("rpmsg: glink: Add support to handle signals command") Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202307160800.sb7gMnL6-lkp@intel.com/ Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20230717165538.1542034-1-quic_bjorande@quicinc.com Signed-off-by: Mathieu Poirier --- drivers/rpmsg/qcom_glink_native.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index e10c05ed21bbd..82d460ff47771 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1070,8 +1070,10 @@ static void qcom_glink_handle_signals(struct qcom_glink *glink, spin_lock_irqsave(&glink->idr_lock, flags); channel = idr_find(&glink->rcids, rcid); spin_unlock_irqrestore(&glink->idr_lock, flags); - if (!channel) + if (!channel) { dev_err(glink->dev, "signal for non-existing channel\n"); + return; + } enable = sigs & NATIVE_DSR_SIG || sigs & NATIVE_CTS_SIG; -- GitLab From 83e824a4a595132f9bd7ac4f5afff857bfc5991e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 18 Jul 2023 13:56:11 +0200 Subject: [PATCH 0257/3445] mtd: spi-nor: Correct flags for Winbond w25q128 The Winbond "w25q128" (actual vendor name W25Q128JV) has exactly the same flags as the sibling device "w25q128jv". The devices both require unlocking to enable write access. The actual product naming between devices vs the Linux strings in winbond.c: 0xef4018: "w25q128" W25Q128JV-IN/IQ/JQ 0xef7018: "w25q128jv" W25Q128JV-IM/JM The latter device, "w25q128jv" supports features named DTQ and QPI, otherwise it is the same. Not having the right flags has the annoying side effect that write access does not work. After this patch I can write to the flash on the Inteno XG6846 router. The flash memory also supports dual and quad SPI modes. This does not currently manifest, but by turning on SFDP parsing, the right SPI modes are emitted in /sys/kernel/debug/spi-nor/spi1.0/capabilities for this chip, so we also turn on this. Since we now have determined that SFDP parsing works on the device, we also detect the geometry using SFDP. After this dmesg and sysfs says: [ 1.062401] spi-nor spi1.0: w25q128 (16384 Kbytes) cat erasesize 65536 (16384*1024)/65536 = 256 sectors spi-nor sysfs: cat jedec_id ef4018 cat manufacturer winbond cat partname w25q128 hexdump -v -C sfdp 00000000 53 46 44 50 05 01 00 ff 00 05 01 10 80 00 00 ff 00000010 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00000020 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00000030 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00000040 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00000050 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00000060 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00000070 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00000080 e5 20 f9 ff ff ff ff 07 44 eb 08 6b 08 3b 42 bb 00000090 fe ff ff ff ff ff 00 00 ff ff 40 eb 0c 20 0f 52 000000a0 10 d8 00 00 36 02 a6 00 82 ea 14 c9 e9 63 76 33 000000b0 7a 75 7a 75 f7 a2 d5 5c 19 f7 4d ff e9 30 f8 80 Cc: stable@vger.kernel.org Suggested-by: Michael Walle Reviewed-by: Michael Walle Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20230718-spi-nor-winbond-w25q128-v5-1-a73653ee46c3@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/winbond.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c index 834d6ba5ce703..63ba8e3a96f51 100644 --- a/drivers/mtd/spi-nor/winbond.c +++ b/drivers/mtd/spi-nor/winbond.c @@ -120,8 +120,9 @@ static const struct flash_info winbond_nor_parts[] = { NO_SFDP_FLAGS(SECT_4K) }, { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16) NO_SFDP_FLAGS(SECT_4K) }, - { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256) - NO_SFDP_FLAGS(SECT_4K) }, + { "w25q128", INFO(0xef4018, 0, 0, 0) + PARSE_SFDP + FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512) NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) .fixups = &w25q256_fixups }, -- GitLab From d4996700abc18efcd7d933ecfbc5f066153e74ff Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 14 Jul 2023 18:07:57 +0300 Subject: [PATCH 0258/3445] mtd: spi-nor: rename method for enabling or disabling octal DTR Having an *_enable(..., bool enable) definition was misleading as the method is used both to enable and to disable the octal DTR mode. Splitting the method in the core in two, one to enable and another to disable the octal DTR mode does not make sense as the method is straight forward and we'd introduce code duplication. Update the core to use: int (*set_octal_dtr)(struct spi_nor *nor, bool enable); Manufacturer drivers use different sequences of commands to enable and disable the octal DTR mode, thus for clarity they shall implement it as: static int manufacturer_snor_set_octal_dtr(struct spi_nor *nor, bool enable) { return enable ? manufacturer_snor_octal_dtr_enable() : manufacturer_snor_octal_dtr_disable(); } Reviewed-by: Michael Walle Link: https://lore.kernel.org/r/20230714150757.15372-1-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/core.c | 12 ++++++------ drivers/mtd/spi-nor/core.h | 4 ++-- drivers/mtd/spi-nor/micron-st.c | 4 ++-- drivers/mtd/spi-nor/spansion.c | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 434c545c0ce40..273258f7e77f3 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -3090,17 +3090,17 @@ static int spi_nor_init_params(struct spi_nor *nor) return 0; } -/** spi_nor_octal_dtr_enable() - enable Octal DTR I/O if needed +/** spi_nor_set_octal_dtr() - enable or disable Octal DTR I/O. * @nor: pointer to a 'struct spi_nor' * @enable: whether to enable or disable Octal DTR * * Return: 0 on success, -errno otherwise. */ -static int spi_nor_octal_dtr_enable(struct spi_nor *nor, bool enable) +static int spi_nor_set_octal_dtr(struct spi_nor *nor, bool enable) { int ret; - if (!nor->params->octal_dtr_enable) + if (!nor->params->set_octal_dtr) return 0; if (!(nor->read_proto == SNOR_PROTO_8_8_8_DTR && @@ -3110,7 +3110,7 @@ static int spi_nor_octal_dtr_enable(struct spi_nor *nor, bool enable) if (!(nor->flags & SNOR_F_IO_MODE_EN_VOLATILE)) return 0; - ret = nor->params->octal_dtr_enable(nor, enable); + ret = nor->params->set_octal_dtr(nor, enable); if (ret) return ret; @@ -3171,7 +3171,7 @@ static int spi_nor_init(struct spi_nor *nor) { int err; - err = spi_nor_octal_dtr_enable(nor, true); + err = spi_nor_set_octal_dtr(nor, true); if (err) { dev_dbg(nor->dev, "octal mode not supported\n"); return err; @@ -3273,7 +3273,7 @@ static int spi_nor_suspend(struct mtd_info *mtd) int ret; /* Disable octal DTR mode if we enabled it. */ - ret = spi_nor_octal_dtr_enable(nor, false); + ret = spi_nor_set_octal_dtr(nor, false); if (ret) dev_err(nor->dev, "suspend() failed\n"); diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index 55b5e7abce6eb..f2fc2cf78e55e 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -364,7 +364,7 @@ struct spi_nor_otp { * @erase_map: the erase map parsed from the SFDP Sector Map Parameter * Table. * @otp: SPI NOR OTP info. - * @octal_dtr_enable: enables SPI NOR octal DTR mode. + * @set_octal_dtr: enables or disables SPI NOR octal DTR mode. * @quad_enable: enables SPI NOR quad mode. * @set_4byte_addr_mode: puts the SPI NOR in 4 byte addressing mode. * @convert_addr: converts an absolute address into something the flash @@ -398,7 +398,7 @@ struct spi_nor_flash_parameter { struct spi_nor_erase_map erase_map; struct spi_nor_otp otp; - int (*octal_dtr_enable)(struct spi_nor *nor, bool enable); + int (*set_octal_dtr)(struct spi_nor *nor, bool enable); int (*quad_enable)(struct spi_nor *nor); int (*set_4byte_addr_mode)(struct spi_nor *nor, bool enable); u32 (*convert_addr)(struct spi_nor *nor, u32 addr); diff --git a/drivers/mtd/spi-nor/micron-st.c b/drivers/mtd/spi-nor/micron-st.c index 4b919756a2055..f79e71d99124c 100644 --- a/drivers/mtd/spi-nor/micron-st.c +++ b/drivers/mtd/spi-nor/micron-st.c @@ -120,7 +120,7 @@ static int micron_st_nor_octal_dtr_dis(struct spi_nor *nor) return 0; } -static int micron_st_nor_octal_dtr_enable(struct spi_nor *nor, bool enable) +static int micron_st_nor_set_octal_dtr(struct spi_nor *nor, bool enable) { return enable ? micron_st_nor_octal_dtr_en(nor) : micron_st_nor_octal_dtr_dis(nor); @@ -128,7 +128,7 @@ static int micron_st_nor_octal_dtr_enable(struct spi_nor *nor, bool enable) static void mt35xu512aba_default_init(struct spi_nor *nor) { - nor->params->octal_dtr_enable = micron_st_nor_octal_dtr_enable; + nor->params->set_octal_dtr = micron_st_nor_set_octal_dtr; } static int mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 36876aa849ede..6d6466a3436e6 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -607,7 +607,7 @@ static struct spi_nor_fixups s25hx_t_fixups = { }; /** - * cypress_nor_octal_dtr_enable() - Enable octal DTR on Cypress flashes. + * cypress_nor_set_octal_dtr() - Enable or disable octal DTR on Cypress flashes. * @nor: pointer to a 'struct spi_nor' * @enable: whether to enable or disable Octal DTR * @@ -616,7 +616,7 @@ static struct spi_nor_fixups s25hx_t_fixups = { * * Return: 0 on success, -errno otherwise. */ -static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable) +static int cypress_nor_set_octal_dtr(struct spi_nor *nor, bool enable) { return enable ? cypress_nor_octal_dtr_en(nor) : cypress_nor_octal_dtr_dis(nor); @@ -667,7 +667,7 @@ static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor, static void s28hx_t_late_init(struct spi_nor *nor) { - nor->params->octal_dtr_enable = cypress_nor_octal_dtr_enable; + nor->params->set_octal_dtr = cypress_nor_set_octal_dtr; cypress_nor_ecc_init(nor); } -- GitLab From d7781232b5b2d049e654d5ead9921dc49090d214 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Mon, 17 Jul 2023 12:20:03 -0700 Subject: [PATCH 0259/3445] Input: da9063 - add wakeup support Mark the IRQ as a wake IRQ so it will be enabled during system suspend. Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20230717192004.1304287-1-samuel.holland@sifive.com Signed-off-by: Dmitry Torokhov --- drivers/input/misc/da9063_onkey.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/input/misc/da9063_onkey.c b/drivers/input/misc/da9063_onkey.c index b14a389600c9e..74808bae326a7 100644 --- a/drivers/input/misc/da9063_onkey.c +++ b/drivers/input/misc/da9063_onkey.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -251,6 +252,14 @@ static int da9063_onkey_probe(struct platform_device *pdev) return error; } + error = dev_pm_set_wake_irq(&pdev->dev, irq); + if (error) + dev_warn(&pdev->dev, + "Failed to set IRQ %d as a wake IRQ: %d\n", + irq, error); + else + device_init_wakeup(&pdev->dev, true); + error = input_register_device(onkey->input); if (error) { dev_err(&pdev->dev, -- GitLab From 62157e11d9a4ca7210bb2b0e8fa0557a6ada7fad Mon Sep 17 00:00:00 2001 From: Kamalesh Babulal Date: Tue, 18 Jul 2023 14:38:34 +0530 Subject: [PATCH 0260/3445] cgroup/misc: update struct members descriptions Update the miscellaneous controller's structure member's description of struct misc_res and struct misc_cg. Signed-off-by: Kamalesh Babulal Signed-off-by: Tejun Heo --- include/linux/misc_cgroup.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/misc_cgroup.h b/include/linux/misc_cgroup.h index c238207d16156..6555c0f571586 100644 --- a/include/linux/misc_cgroup.h +++ b/include/linux/misc_cgroup.h @@ -31,7 +31,7 @@ struct misc_cg; * struct misc_res: Per cgroup per misc type resource * @max: Maximum limit on the resource. * @usage: Current usage of the resource. - * @failed: True if charged failed for the resource in a cgroup. + * @events: Number of times, the resource limit exceeded. */ struct misc_res { unsigned long max; @@ -42,6 +42,7 @@ struct misc_res { /** * struct misc_cg - Miscellaneous controller's cgroup structure. * @css: cgroup subsys state object. + * @events_file: Handle for the misc resources events file. * @res: Array of misc resources usage in the cgroup. */ struct misc_cg { -- GitLab From 32bf85c60ca3584a7ba3bef19da2779b73b2e7d6 Mon Sep 17 00:00:00 2001 From: Haitao Huang Date: Mon, 17 Jul 2023 18:08:45 -0700 Subject: [PATCH 0261/3445] cgroup/misc: Change counters to be explicit 64bit types So the variables can account for resources of huge quantities even on 32-bit machines. Signed-off-by: Haitao Huang Signed-off-by: Tejun Heo --- include/linux/misc_cgroup.h | 25 ++++++++--------- kernel/cgroup/misc.c | 55 ++++++++++++++++++------------------- 2 files changed, 38 insertions(+), 42 deletions(-) diff --git a/include/linux/misc_cgroup.h b/include/linux/misc_cgroup.h index 6555c0f571586..e799b1f8d05bb 100644 --- a/include/linux/misc_cgroup.h +++ b/include/linux/misc_cgroup.h @@ -34,9 +34,9 @@ struct misc_cg; * @events: Number of times, the resource limit exceeded. */ struct misc_res { - unsigned long max; - atomic_long_t usage; - atomic_long_t events; + u64 max; + atomic64_t usage; + atomic64_t events; }; /** @@ -54,12 +54,10 @@ struct misc_cg { struct misc_res res[MISC_CG_RES_TYPES]; }; -unsigned long misc_cg_res_total_usage(enum misc_res_type type); -int misc_cg_set_capacity(enum misc_res_type type, unsigned long capacity); -int misc_cg_try_charge(enum misc_res_type type, struct misc_cg *cg, - unsigned long amount); -void misc_cg_uncharge(enum misc_res_type type, struct misc_cg *cg, - unsigned long amount); +u64 misc_cg_res_total_usage(enum misc_res_type type); +int misc_cg_set_capacity(enum misc_res_type type, u64 capacity); +int misc_cg_try_charge(enum misc_res_type type, struct misc_cg *cg, u64 amount); +void misc_cg_uncharge(enum misc_res_type type, struct misc_cg *cg, u64 amount); /** * css_misc() - Get misc cgroup from the css. @@ -100,27 +98,26 @@ static inline void put_misc_cg(struct misc_cg *cg) #else /* !CONFIG_CGROUP_MISC */ -static inline unsigned long misc_cg_res_total_usage(enum misc_res_type type) +static inline u64 misc_cg_res_total_usage(enum misc_res_type type) { return 0; } -static inline int misc_cg_set_capacity(enum misc_res_type type, - unsigned long capacity) +static inline int misc_cg_set_capacity(enum misc_res_type type, u64 capacity) { return 0; } static inline int misc_cg_try_charge(enum misc_res_type type, struct misc_cg *cg, - unsigned long amount) + u64 amount) { return 0; } static inline void misc_cg_uncharge(enum misc_res_type type, struct misc_cg *cg, - unsigned long amount) + u64 amount) { } diff --git a/kernel/cgroup/misc.c b/kernel/cgroup/misc.c index ae2f4dd47508d..abbe9aa5cdd17 100644 --- a/kernel/cgroup/misc.c +++ b/kernel/cgroup/misc.c @@ -14,7 +14,7 @@ #include #define MAX_STR "max" -#define MAX_NUM ULONG_MAX +#define MAX_NUM U64_MAX /* Miscellaneous res name, keep it in sync with enum misc_res_type */ static const char *const misc_res_name[] = { @@ -37,7 +37,7 @@ static struct misc_cg root_cg; * more than the actual capacity. We are using Limits resource distribution * model of cgroup for miscellaneous controller. */ -static unsigned long misc_res_capacity[MISC_CG_RES_TYPES]; +static u64 misc_res_capacity[MISC_CG_RES_TYPES]; /** * parent_misc() - Get the parent of the passed misc cgroup. @@ -74,10 +74,10 @@ static inline bool valid_type(enum misc_res_type type) * Context: Any context. * Return: Current total usage of the resource. */ -unsigned long misc_cg_res_total_usage(enum misc_res_type type) +u64 misc_cg_res_total_usage(enum misc_res_type type) { if (valid_type(type)) - return atomic_long_read(&root_cg.res[type].usage); + return atomic64_read(&root_cg.res[type].usage); return 0; } @@ -95,7 +95,7 @@ EXPORT_SYMBOL_GPL(misc_cg_res_total_usage); * * %0 - Successfully registered the capacity. * * %-EINVAL - If @type is invalid. */ -int misc_cg_set_capacity(enum misc_res_type type, unsigned long capacity) +int misc_cg_set_capacity(enum misc_res_type type, u64 capacity) { if (!valid_type(type)) return -EINVAL; @@ -114,9 +114,9 @@ EXPORT_SYMBOL_GPL(misc_cg_set_capacity); * Context: Any context. */ static void misc_cg_cancel_charge(enum misc_res_type type, struct misc_cg *cg, - unsigned long amount) + u64 amount) { - WARN_ONCE(atomic_long_add_negative(-amount, &cg->res[type].usage), + WARN_ONCE(atomic64_add_negative(-amount, &cg->res[type].usage), "misc cgroup resource %s became less than 0", misc_res_name[type]); } @@ -137,13 +137,12 @@ static void misc_cg_cancel_charge(enum misc_res_type type, struct misc_cg *cg, * * -EBUSY - If max limit will be crossed or total usage will be more than the * capacity. */ -int misc_cg_try_charge(enum misc_res_type type, struct misc_cg *cg, - unsigned long amount) +int misc_cg_try_charge(enum misc_res_type type, struct misc_cg *cg, u64 amount) { struct misc_cg *i, *j; int ret; struct misc_res *res; - int new_usage; + s64 new_usage; if (!(valid_type(type) && cg && READ_ONCE(misc_res_capacity[type]))) return -EINVAL; @@ -154,7 +153,7 @@ int misc_cg_try_charge(enum misc_res_type type, struct misc_cg *cg, for (i = cg; i; i = parent_misc(i)) { res = &i->res[type]; - new_usage = atomic_long_add_return(amount, &res->usage); + new_usage = atomic64_add_return(amount, &res->usage); if (new_usage > READ_ONCE(res->max) || new_usage > READ_ONCE(misc_res_capacity[type])) { ret = -EBUSY; @@ -165,7 +164,7 @@ int misc_cg_try_charge(enum misc_res_type type, struct misc_cg *cg, err_charge: for (j = i; j; j = parent_misc(j)) { - atomic_long_inc(&j->res[type].events); + atomic64_inc(&j->res[type].events); cgroup_file_notify(&j->events_file); } @@ -184,8 +183,7 @@ EXPORT_SYMBOL_GPL(misc_cg_try_charge); * * Context: Any context. */ -void misc_cg_uncharge(enum misc_res_type type, struct misc_cg *cg, - unsigned long amount) +void misc_cg_uncharge(enum misc_res_type type, struct misc_cg *cg, u64 amount) { struct misc_cg *i; @@ -209,7 +207,7 @@ static int misc_cg_max_show(struct seq_file *sf, void *v) { int i; struct misc_cg *cg = css_misc(seq_css(sf)); - unsigned long max; + u64 max; for (i = 0; i < MISC_CG_RES_TYPES; i++) { if (READ_ONCE(misc_res_capacity[i])) { @@ -217,7 +215,7 @@ static int misc_cg_max_show(struct seq_file *sf, void *v) if (max == MAX_NUM) seq_printf(sf, "%s max\n", misc_res_name[i]); else - seq_printf(sf, "%s %lu\n", misc_res_name[i], + seq_printf(sf, "%s %llu\n", misc_res_name[i], max); } } @@ -241,13 +239,13 @@ static int misc_cg_max_show(struct seq_file *sf, void *v) * Return: * * >= 0 - Number of bytes processed in the input. * * -EINVAL - If buf is not valid. - * * -ERANGE - If number is bigger than the unsigned long capacity. + * * -ERANGE - If number is bigger than the u64 capacity. */ static ssize_t misc_cg_max_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { struct misc_cg *cg; - unsigned long max; + u64 max; int ret = 0, i; enum misc_res_type type = MISC_CG_RES_TYPES; char *token; @@ -271,7 +269,7 @@ static ssize_t misc_cg_max_write(struct kernfs_open_file *of, char *buf, if (!strcmp(MAX_STR, buf)) { max = MAX_NUM; } else { - ret = kstrtoul(buf, 0, &max); + ret = kstrtou64(buf, 0, &max); if (ret) return ret; } @@ -297,13 +295,13 @@ static ssize_t misc_cg_max_write(struct kernfs_open_file *of, char *buf, static int misc_cg_current_show(struct seq_file *sf, void *v) { int i; - unsigned long usage; + u64 usage; struct misc_cg *cg = css_misc(seq_css(sf)); for (i = 0; i < MISC_CG_RES_TYPES; i++) { - usage = atomic_long_read(&cg->res[i].usage); + usage = atomic64_read(&cg->res[i].usage); if (READ_ONCE(misc_res_capacity[i]) || usage) - seq_printf(sf, "%s %lu\n", misc_res_name[i], usage); + seq_printf(sf, "%s %llu\n", misc_res_name[i], usage); } return 0; @@ -322,12 +320,12 @@ static int misc_cg_current_show(struct seq_file *sf, void *v) static int misc_cg_capacity_show(struct seq_file *sf, void *v) { int i; - unsigned long cap; + u64 cap; for (i = 0; i < MISC_CG_RES_TYPES; i++) { cap = READ_ONCE(misc_res_capacity[i]); if (cap) - seq_printf(sf, "%s %lu\n", misc_res_name[i], cap); + seq_printf(sf, "%s %llu\n", misc_res_name[i], cap); } return 0; @@ -336,12 +334,13 @@ static int misc_cg_capacity_show(struct seq_file *sf, void *v) static int misc_events_show(struct seq_file *sf, void *v) { struct misc_cg *cg = css_misc(seq_css(sf)); - unsigned long events, i; + u64 events; + int i; for (i = 0; i < MISC_CG_RES_TYPES; i++) { - events = atomic_long_read(&cg->res[i].events); + events = atomic64_read(&cg->res[i].events); if (READ_ONCE(misc_res_capacity[i]) || events) - seq_printf(sf, "%s.max %lu\n", misc_res_name[i], events); + seq_printf(sf, "%s.max %llu\n", misc_res_name[i], events); } return 0; } @@ -397,7 +396,7 @@ misc_cg_alloc(struct cgroup_subsys_state *parent_css) for (i = 0; i < MISC_CG_RES_TYPES; i++) { WRITE_ONCE(cg->res[i].max, MAX_NUM); - atomic_long_set(&cg->res[i].usage, 0); + atomic64_set(&cg->res[i].usage, 0); } return &cg->css; -- GitLab From 21c133be0266b4e7aaf184175d61f5b1824a8769 Mon Sep 17 00:00:00 2001 From: Artur Weber Date: Tue, 18 Jul 2023 23:15:32 -0700 Subject: [PATCH 0262/3445] dt-bindings: mms114: Add linux,keycodes property for touch keys MELFAS MMS114 and similar touchscreens have support for touch keys. Add the linux,keycodes property which can be used to set up the keycodes for the touch keys. Acked-by: Conor Dooley Signed-off-by: Artur Weber Link: https://lore.kernel.org/r/20230714100424.29798-2-aweber.kernel@gmail.com Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/touchscreen/melfas,mms114.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/input/touchscreen/melfas,mms114.yaml b/Documentation/devicetree/bindings/input/touchscreen/melfas,mms114.yaml index fdd02898e2492..07f9dd6b1c9c4 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/melfas,mms114.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/melfas,mms114.yaml @@ -52,6 +52,11 @@ properties: touchscreen-swapped-x-y: true touchscreen-max-pressure: true + linux,keycodes: + description: Keycodes for the touch keys + minItems: 1 + maxItems: 15 + additionalProperties: false required: -- GitLab From bf93349b11ab6f4a5861fbabe01236bf3d58075a Mon Sep 17 00:00:00 2001 From: Artur Weber Date: Tue, 18 Jul 2023 23:15:43 -0700 Subject: [PATCH 0263/3445] Input: mms114 - add support for touch keys MELFAS MMS114 and similar touchscreens have support for touch keys. Enable support of them in the driver. The keycodes to emit can be controlled by the linux,keycodes DT property. Sidenote - the MAX_TOUCHKEYS value is set to 15, as that's the maximum value that the ID field can contain. I don't have access to any datasheets that could confirm or deny whether this is accurate. Most downstream drivers I've been able to find only use up to 2 keys (though I did find a driver that mentioned up to 4, but only 2 were used). They don't have any checks for a maximum keycode value, it is just extracted from the ID bits (0xf mask). The drivers I've been able to find also don't use touch ID 0; I assume that it is never used, so the keycodes provided in the DT start from touch ID 1. I suppose this is in-line with the regular behavior for touch IDs in touchscreen events, as there the provided touch ID is always lowered by 1, which would cause an overflow if it was 0... Just in case, we quietly return if the touch ID is set to 0 here. The implementation of the linux,keycodes property handling code was adapted from the msg2638 driver. Signed-off-by: Artur Weber Link: https://lore.kernel.org/r/20230714100424.29798-3-aweber.kernel@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/mms114.c | 88 +++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 7 deletions(-) diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index 6109cf7e779a2..af233b6a16d9a 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -42,6 +42,7 @@ /* Touchscreen absolute values */ #define MMS114_MAX_AREA 0xff +#define MMS114_MAX_TOUCHKEYS 15 #define MMS114_MAX_TOUCH 10 #define MMS114_EVENT_SIZE 8 #define MMS136_EVENT_SIZE 6 @@ -69,6 +70,9 @@ struct mms114_data { unsigned int contact_threshold; unsigned int moving_threshold; + u32 keycodes[MMS114_MAX_TOUCHKEYS]; + int num_keycodes; + /* Use cache data for mode control register(write only) */ u8 cache_mode_control; }; @@ -166,11 +170,6 @@ static void mms114_process_mt(struct mms114_data *data, struct mms114_touch *tou return; } - if (touch->type != MMS114_TYPE_TOUCHSCREEN) { - dev_err(&client->dev, "Wrong touch type (%d)\n", touch->type); - return; - } - id = touch->id - 1; x = touch->x_lo | touch->x_hi << 8; y = touch->y_lo | touch->y_hi << 8; @@ -190,9 +189,33 @@ static void mms114_process_mt(struct mms114_data *data, struct mms114_touch *tou } } +static void mms114_process_touchkey(struct mms114_data *data, + struct mms114_touch *touch) +{ + struct i2c_client *client = data->client; + struct input_dev *input_dev = data->input_dev; + unsigned int keycode_id; + + if (touch->id == 0) + return; + + if (touch->id > data->num_keycodes) { + dev_err(&client->dev, "Wrong touch id for touchkey (%d)\n", + touch->id); + return; + } + + keycode_id = touch->id - 1; + dev_dbg(&client->dev, "keycode id: %d, pressed: %d\n", keycode_id, + touch->pressed); + + input_report_key(input_dev, data->keycodes[keycode_id], touch->pressed); +} + static irqreturn_t mms114_interrupt(int irq, void *dev_id) { struct mms114_data *data = dev_id; + struct i2c_client *client = data->client; struct input_dev *input_dev = data->input_dev; struct mms114_touch touch[MMS114_MAX_TOUCH]; int packet_size; @@ -222,8 +245,22 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id) if (error < 0) goto out; - for (index = 0; index < touch_size; index++) - mms114_process_mt(data, touch + index); + for (index = 0; index < touch_size; index++) { + switch (touch[index].type) { + case MMS114_TYPE_TOUCHSCREEN: + mms114_process_mt(data, touch + index); + break; + + case MMS114_TYPE_TOUCHKEY: + mms114_process_touchkey(data, touch + index); + break; + + default: + dev_err(&client->dev, "Wrong touch type (%d)\n", + touch[index].type); + break; + } + } input_mt_report_pointer_emulation(data->input_dev, true); input_sync(data->input_dev); @@ -445,6 +482,7 @@ static int mms114_probe(struct i2c_client *client) struct input_dev *input_dev; const void *match_data; int error; + int i; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "Not supported I2C adapter\n"); @@ -468,6 +506,42 @@ static int mms114_probe(struct i2c_client *client) data->type = (enum mms_type)match_data; + data->num_keycodes = device_property_count_u32(&client->dev, + "linux,keycodes"); + if (data->num_keycodes == -EINVAL) { + data->num_keycodes = 0; + } else if (data->num_keycodes < 0) { + dev_err(&client->dev, + "Unable to parse linux,keycodes property: %d\n", + data->num_keycodes); + return data->num_keycodes; + } else if (data->num_keycodes > MMS114_MAX_TOUCHKEYS) { + dev_warn(&client->dev, + "Found %d linux,keycodes but max is %d, ignoring the rest\n", + data->num_keycodes, MMS114_MAX_TOUCHKEYS); + data->num_keycodes = MMS114_MAX_TOUCHKEYS; + } + + if (data->num_keycodes > 0) { + error = device_property_read_u32_array(&client->dev, + "linux,keycodes", + data->keycodes, + data->num_keycodes); + if (error) { + dev_err(&client->dev, + "Unable to read linux,keycodes values: %d\n", + error); + return error; + } + + input_dev->keycode = data->keycodes; + input_dev->keycodemax = data->num_keycodes; + input_dev->keycodesize = sizeof(data->keycodes[0]); + for (i = 0; i < data->num_keycodes; i++) + input_set_capability(input_dev, + EV_KEY, data->keycodes[i]); + } + input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X); input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y); input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0); -- GitLab From b3d2b014b259ba758d72d7026685091bde1cf2d6 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 18 Jul 2023 21:38:09 +0200 Subject: [PATCH 0264/3445] RDMA/irdma: Fix building without IPv6 The new irdma_iw_get_vlan_prio() function requires IPv6 support to build: x86_64-linux-ld: drivers/infiniband/hw/irdma/cm.o: in function `irdma_iw_get_vlan_prio': cm.c:(.text+0x2832): undefined reference to `ipv6_chk_addr' Add a compile-time check in the same way as elsewhere in this file to avoid this by conditionally leaving out the ipv6 specific bits. Fixes: f877f22ac1e9b ("RDMA/irdma: Implement egress VLAN priority") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20230718193835.3546684-1-arnd@kernel.org Acked-by: Shiraz Saleem Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/irdma/cm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/irdma/cm.c b/drivers/infiniband/hw/irdma/cm.c index 6b71b67ce9ff0..8ea55c6a3fba5 100644 --- a/drivers/infiniband/hw/irdma/cm.c +++ b/drivers/infiniband/hw/irdma/cm.c @@ -1562,7 +1562,7 @@ static u8 irdma_iw_get_vlan_prio(u32 *loc_addr, u8 prio, bool ipv4) rcu_read_lock(); if (ipv4) { ndev = ip_dev_find(&init_net, htonl(loc_addr[0])); - } else { + } else if (IS_ENABLED(CONFIG_IPV6)) { struct net_device *ip_dev; struct in6_addr laddr6; -- GitLab From b4f78ff746ec5274fffa92fa2a4dc531360b5016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 14 Jul 2023 22:56:14 +0200 Subject: [PATCH 0265/3445] pwm: Use a consistent name for pwm_chip pointers in the core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most variables of type struct pwm_chip * are named "chip", there are only three outliers called "pc". Change these three to "chip", too, for consistency. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 28 ++++++++++++++-------------- include/linux/pwm.h | 6 +++--- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 3dacceaef4a9b..8c798753c0164 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -127,28 +127,28 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label) } struct pwm_device * -of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args) +of_pwm_xlate_with_flags(struct pwm_chip *chip, const struct of_phandle_args *args) { struct pwm_device *pwm; - if (pc->of_pwm_n_cells < 2) + if (chip->of_pwm_n_cells < 2) return ERR_PTR(-EINVAL); /* flags in the third cell are optional */ if (args->args_count < 2) return ERR_PTR(-EINVAL); - if (args->args[0] >= pc->npwm) + if (args->args[0] >= chip->npwm) return ERR_PTR(-EINVAL); - pwm = pwm_request_from_chip(pc, args->args[0], NULL); + pwm = pwm_request_from_chip(chip, args->args[0], NULL); if (IS_ERR(pwm)) return pwm; pwm->args.period = args->args[1]; pwm->args.polarity = PWM_POLARITY_NORMAL; - if (pc->of_pwm_n_cells >= 3) { + if (chip->of_pwm_n_cells >= 3) { if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED) pwm->args.polarity = PWM_POLARITY_INVERSED; } @@ -158,18 +158,18 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args) EXPORT_SYMBOL_GPL(of_pwm_xlate_with_flags); struct pwm_device * -of_pwm_single_xlate(struct pwm_chip *pc, const struct of_phandle_args *args) +of_pwm_single_xlate(struct pwm_chip *chip, const struct of_phandle_args *args) { struct pwm_device *pwm; - if (pc->of_pwm_n_cells < 1) + if (chip->of_pwm_n_cells < 1) return ERR_PTR(-EINVAL); /* validate that one cell is specified, optionally with flags */ if (args->args_count != 1 && args->args_count != 2) return ERR_PTR(-EINVAL); - pwm = pwm_request_from_chip(pc, 0, NULL); + pwm = pwm_request_from_chip(chip, 0, NULL); if (IS_ERR(pwm)) return pwm; @@ -692,7 +692,7 @@ static struct pwm_device *of_pwm_get(struct device *dev, struct device_node *np, struct pwm_device *pwm = NULL; struct of_phandle_args args; struct device_link *dl; - struct pwm_chip *pc; + struct pwm_chip *chip; int index = 0; int err; @@ -709,16 +709,16 @@ static struct pwm_device *of_pwm_get(struct device *dev, struct device_node *np, return ERR_PTR(err); } - pc = fwnode_to_pwmchip(of_fwnode_handle(args.np)); - if (IS_ERR(pc)) { - if (PTR_ERR(pc) != -EPROBE_DEFER) + chip = fwnode_to_pwmchip(of_fwnode_handle(args.np)); + if (IS_ERR(chip)) { + if (PTR_ERR(chip) != -EPROBE_DEFER) pr_err("%s(): PWM chip not found\n", __func__); - pwm = ERR_CAST(pc); + pwm = ERR_CAST(chip); goto put; } - pwm = pc->of_xlate(pc, &args); + pwm = chip->of_xlate(chip, &args); if (IS_ERR(pwm)) goto put; diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 04ae1d9073a74..d2f9f690a9c14 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -298,7 +298,7 @@ struct pwm_chip { int base; unsigned int npwm; - struct pwm_device * (*of_xlate)(struct pwm_chip *pc, + struct pwm_device * (*of_xlate)(struct pwm_chip *chip, const struct of_phandle_args *args); unsigned int of_pwm_n_cells; @@ -395,9 +395,9 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip, unsigned int index, const char *label); -struct pwm_device *of_pwm_xlate_with_flags(struct pwm_chip *pc, +struct pwm_device *of_pwm_xlate_with_flags(struct pwm_chip *chip, const struct of_phandle_args *args); -struct pwm_device *of_pwm_single_xlate(struct pwm_chip *pc, +struct pwm_device *of_pwm_single_xlate(struct pwm_chip *chip, const struct of_phandle_args *args); struct pwm_device *pwm_get(struct device *dev, const char *con_id); -- GitLab From 6d3e0d8cc63221dec670d0ee92ac57961581e975 Mon Sep 17 00:00:00 2001 From: John Ogness Date: Mon, 17 Jul 2023 21:52:01 +0206 Subject: [PATCH 0266/3445] kdb: Do not assume write() callback available It is allowed for consoles to not provide a write() callback. For example ttynull does this. Check if a write() callback is available before using it. Signed-off-by: John Ogness Reviewed-by: Petr Mladek Reviewed-by: Douglas Anderson Reviewed-by: Daniel Thompson Acked-by: Daniel Thompson Reviewed-by: Sergey Senozhatsky Signed-off-by: Petr Mladek Link: https://lore.kernel.org/r/20230717194607.145135-2-john.ogness@linutronix.de --- kernel/debug/kdb/kdb_io.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c index 5c7e9ba7cd6b2..e9139dfc1f0a8 100644 --- a/kernel/debug/kdb/kdb_io.c +++ b/kernel/debug/kdb/kdb_io.c @@ -576,6 +576,8 @@ static void kdb_msg_write(const char *msg, int msg_len) continue; if (c == dbg_io_ops->cons) continue; + if (!c->write) + continue; /* * Set oops_in_progress to encourage the console drivers to * disregard their internal spin locks: in the current calling -- GitLab From 7b23a66db55ed0a55b020e913f0d6f6d52a1ad2c Mon Sep 17 00:00:00 2001 From: John Ogness Date: Mon, 17 Jul 2023 21:52:02 +0206 Subject: [PATCH 0267/3445] printk: Reduce console_unblank() usage in unsafe scenarios A semaphore is not NMI-safe, even when using down_trylock(). Both down_trylock() and up() are using internal spinlocks and up() might even call wake_up_process(). In the panic() code path it gets even worse because the internal spinlocks of the semaphore may have been taken by a CPU that has been stopped. To reduce the risk of deadlocks caused by the console semaphore in the panic path, make the following changes: - First check if any consoles have implemented the unblank() callback. If not, then there is no reason to take the console semaphore anyway. (This check is also useful for the non-panic path since the locking/unlocking of the console lock can be quite expensive due to console printing.) - If the panic path is in NMI context, bail out without attempting to take the console semaphore or calling any unblank() callbacks. Bailing out is acceptable because console_unblank() would already bail out if the console semaphore is contended. The alternative of ignoring the console semaphore and calling the unblank() callbacks anyway is a bad idea because these callbacks are also not NMI-safe. If consoles with unblank() callbacks exist and console_unblank() is called from a non-NMI panic context, it will still attempt a down_trylock(). This could still result in a deadlock if one of the stopped CPUs is holding the semaphore internal spinlock. But this is a risk that the kernel has been (and continues to be) willing to take. Signed-off-by: John Ogness Reviewed-by: Sergey Senozhatsky Reviewed-by: Petr Mladek Signed-off-by: Petr Mladek Link: https://lore.kernel.org/r/20230717194607.145135-3-john.ogness@linutronix.de --- kernel/printk/printk.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 9644f6e5bf15b..7aa9dbee12e87 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -3043,9 +3043,27 @@ EXPORT_SYMBOL(console_conditional_schedule); void console_unblank(void) { + bool found_unblank = false; struct console *c; int cookie; + /* + * First check if there are any consoles implementing the unblank() + * callback. If not, there is no reason to continue and take the + * console lock, which in particular can be dangerous if + * @oops_in_progress is set. + */ + cookie = console_srcu_read_lock(); + for_each_console_srcu(c) { + if ((console_srcu_read_flags(c) & CON_ENABLED) && c->unblank) { + found_unblank = true; + break; + } + } + console_srcu_read_unlock(cookie); + if (!found_unblank) + return; + /* * Stop console printing because the unblank() callback may * assume the console is not within its write() callback. @@ -3054,6 +3072,16 @@ void console_unblank(void) * In that case, attempt a trylock as best-effort. */ if (oops_in_progress) { + /* Semaphores are not NMI-safe. */ + if (in_nmi()) + return; + + /* + * Attempting to trylock the console lock can deadlock + * if another CPU was stopped while modifying the + * semaphore. "Hope and pray" that this is not the + * current situation. + */ if (down_trylock_console_sem() != 0) return; } else -- GitLab From 51a1d258e50e03a0216bf42b6af9ff34ec402ac1 Mon Sep 17 00:00:00 2001 From: John Ogness Date: Mon, 17 Jul 2023 21:52:03 +0206 Subject: [PATCH 0268/3445] printk: Keep non-panic-CPUs out of console lock When in a panic situation, non-panic CPUs should avoid holding the console lock so as not to contend with the panic CPU. This is already implemented with abandon_console_lock_in_panic(), which is checked after each printed line. However, non-panic CPUs should also avoid trying to acquire the console lock during a panic. Modify console_trylock() to fail and console_lock() to block() when called from a non-panic CPU during a panic. Signed-off-by: John Ogness Reviewed-by: Sergey Senozhatsky Reviewed-by: Petr Mladek Signed-off-by: Petr Mladek Link: https://lore.kernel.org/r/20230717194607.145135-4-john.ogness@linutronix.de --- kernel/printk/printk.c | 45 ++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 7aa9dbee12e87..7219991885e6f 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2583,6 +2583,25 @@ static int console_cpu_notify(unsigned int cpu) return 0; } +/* + * Return true when this CPU should unlock console_sem without pushing all + * messages to the console. This reduces the chance that the console is + * locked when the panic CPU tries to use it. + */ +static bool abandon_console_lock_in_panic(void) +{ + if (!panic_in_progress()) + return false; + + /* + * We can use raw_smp_processor_id() here because it is impossible for + * the task to be migrated to the panic_cpu, or away from it. If + * panic_cpu has already been set, and we're not currently executing on + * that CPU, then we never will be. + */ + return atomic_read(&panic_cpu) != raw_smp_processor_id(); +} + /** * console_lock - block the console subsystem from printing * @@ -2595,6 +2614,10 @@ void console_lock(void) { might_sleep(); + /* On panic, the console_lock must be left to the panic cpu. */ + while (abandon_console_lock_in_panic()) + msleep(1000); + down_console_sem(); if (console_suspended) return; @@ -2613,6 +2636,9 @@ EXPORT_SYMBOL(console_lock); */ int console_trylock(void) { + /* On panic, the console_lock must be left to the panic cpu. */ + if (abandon_console_lock_in_panic()) + return 0; if (down_trylock_console_sem()) return 0; if (console_suspended) { @@ -2631,25 +2657,6 @@ int is_console_locked(void) } EXPORT_SYMBOL(is_console_locked); -/* - * Return true when this CPU should unlock console_sem without pushing all - * messages to the console. This reduces the chance that the console is - * locked when the panic CPU tries to use it. - */ -static bool abandon_console_lock_in_panic(void) -{ - if (!panic_in_progress()) - return false; - - /* - * We can use raw_smp_processor_id() here because it is impossible for - * the task to be migrated to the panic_cpu, or away from it. If - * panic_cpu has already been set, and we're not currently executing on - * that CPU, then we never will be. - */ - return atomic_read(&panic_cpu) != raw_smp_processor_id(); -} - /* * Check if the given console is currently capable and allowed to print * records. -- GitLab From eacb04ff3c5b8662a65f380ae450250698448cff Mon Sep 17 00:00:00 2001 From: John Ogness Date: Mon, 17 Jul 2023 21:52:04 +0206 Subject: [PATCH 0269/3445] printk: Do not take console lock for console_flush_on_panic() Currently console_flush_on_panic() will attempt to acquire the console lock when flushing the buffer on panic. If it fails to acquire the lock, it continues anyway because this is the last chance to get any pending records printed. The reason why the console lock was attempted at all was to prevent any other CPUs from acquiring the console lock for printing while the panic CPU was printing. But as of the previous commit, non-panic CPUs will no longer attempt to acquire the console lock in a panic situation. Therefore it is no longer strictly necessary for a panic CPU to acquire the console lock. Avoiding taking the console lock when flushing in panic has the additional benefit of avoiding possible deadlocks due to semaphore usage in NMI context (semaphores are not NMI-safe) and avoiding possible deadlocks if another CPU accesses the semaphore and is stopped while holding one of the semaphore's internal spinlocks. Signed-off-by: John Ogness Reviewed-by: Sergey Senozhatsky Reviewed-by: Petr Mladek Signed-off-by: Petr Mladek Link: https://lore.kernel.org/r/20230717194607.145135-5-john.ogness@linutronix.de --- kernel/printk/printk.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 7219991885e6f..51445e8ea7309 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -3118,14 +3118,24 @@ void console_unblank(void) */ void console_flush_on_panic(enum con_flush_mode mode) { + bool handover; + u64 next_seq; + /* - * If someone else is holding the console lock, trylock will fail - * and may_schedule may be set. Ignore and proceed to unlock so - * that messages are flushed out. As this can be called from any - * context and we don't want to get preempted while flushing, - * ensure may_schedule is cleared. + * Ignore the console lock and flush out the messages. Attempting a + * trylock would not be useful because: + * + * - if it is contended, it must be ignored anyway + * - console_lock() and console_trylock() block and fail + * respectively in panic for non-panic CPUs + * - semaphores are not NMI-safe + */ + + /* + * If another context is holding the console lock, + * @console_may_schedule might be set. Clear it so that + * this context does not call cond_resched() while flushing. */ - console_trylock(); console_may_schedule = 0; if (mode == CONSOLE_REPLAY_ALL) { @@ -3138,15 +3148,15 @@ void console_flush_on_panic(enum con_flush_mode mode) cookie = console_srcu_read_lock(); for_each_console_srcu(c) { /* - * If the above console_trylock() failed, this is an - * unsynchronized assignment. But in that case, the + * This is an unsynchronized assignment, but the * kernel is in "hope and pray" mode anyway. */ c->seq = seq; } console_srcu_read_unlock(cookie); } - console_unlock(); + + console_flush_all(false, &next_seq, &handover); } /* -- GitLab From 696ffaf50e1f8dbc66223ff614473f945f5fb8d8 Mon Sep 17 00:00:00 2001 From: John Ogness Date: Mon, 17 Jul 2023 21:52:05 +0206 Subject: [PATCH 0270/3445] printk: Consolidate console deferred printing Printing to consoles can be deferred for several reasons: - explicitly with printk_deferred() - printk() in NMI context - recursive printk() calls The current implementation is not consistent. For printk_deferred(), irq work is scheduled twice. For NMI und recursive, panic CPU suppression and caller delays are not properly enforced. Correct these inconsistencies by consolidating the deferred printing code so that vprintk_deferred() is the top-level function for deferred printing and vprintk_emit() will perform whichever irq_work queueing is appropriate. Also add kerneldoc for wake_up_klogd() and defer_console_output() to clarify their differences and appropriate usage. Signed-off-by: John Ogness Reviewed-by: Sergey Senozhatsky Reviewed-by: Petr Mladek Signed-off-by: Petr Mladek Link: https://lore.kernel.org/r/20230717194607.145135-6-john.ogness@linutronix.de --- kernel/printk/printk.c | 35 ++++++++++++++++++++++++++++------- kernel/printk/printk_safe.c | 9 ++------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 51445e8ea7309..6e853a1441a7c 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2306,7 +2306,11 @@ asmlinkage int vprintk_emit(int facility, int level, preempt_enable(); } - wake_up_klogd(); + if (in_sched) + defer_console_output(); + else + wake_up_klogd(); + return printed_len; } EXPORT_SYMBOL(vprintk_emit); @@ -3841,11 +3845,33 @@ static void __wake_up_klogd(int val) preempt_enable(); } +/** + * wake_up_klogd - Wake kernel logging daemon + * + * Use this function when new records have been added to the ringbuffer + * and the console printing of those records has already occurred or is + * known to be handled by some other context. This function will only + * wake the logging daemon. + * + * Context: Any context. + */ void wake_up_klogd(void) { __wake_up_klogd(PRINTK_PENDING_WAKEUP); } +/** + * defer_console_output - Wake kernel logging daemon and trigger + * console printing in a deferred context + * + * Use this function when new records have been added to the ringbuffer, + * this context is responsible for console printing those records, but + * the current context is not allowed to perform the console printing. + * Trigger an irq_work context to perform the console printing. This + * function also wakes the logging daemon. + * + * Context: Any context. + */ void defer_console_output(void) { /* @@ -3862,12 +3888,7 @@ void printk_trigger_flush(void) int vprintk_deferred(const char *fmt, va_list args) { - int r; - - r = vprintk_emit(0, LOGLEVEL_SCHED, NULL, fmt, args); - defer_console_output(); - - return r; + return vprintk_emit(0, LOGLEVEL_SCHED, NULL, fmt, args); } int _printk_deferred(const char *fmt, ...) diff --git a/kernel/printk/printk_safe.c b/kernel/printk/printk_safe.c index ef0f9a2044da1..6d10927a07d83 100644 --- a/kernel/printk/printk_safe.c +++ b/kernel/printk/printk_safe.c @@ -38,13 +38,8 @@ asmlinkage int vprintk(const char *fmt, va_list args) * Use the main logbuf even in NMI. But avoid calling console * drivers that might have their own locks. */ - if (this_cpu_read(printk_context) || in_nmi()) { - int len; - - len = vprintk_store(0, LOGLEVEL_DEFAULT, NULL, fmt, args); - defer_console_output(); - return len; - } + if (this_cpu_read(printk_context) || in_nmi()) + return vprintk_deferred(fmt, args); /* No obstacles. */ return vprintk_default(fmt, args); -- GitLab From 9e70a5e109a4a23367810de09be826c52d27ee2f Mon Sep 17 00:00:00 2001 From: John Ogness Date: Mon, 17 Jul 2023 21:52:06 +0206 Subject: [PATCH 0271/3445] printk: Add per-console suspended state Currently the global @console_suspended is used to determine if consoles are in a suspended state. Its primary purpose is to allow usage of the console_lock when suspended without causing console printing. It is synchronized by the console_lock. Rather than relying on the console_lock to determine suspended state, make it an official per-console state that is set within console->flags. This allows the state to be queried via SRCU. Remove @console_suspended. Console printing will still be avoided when suspended because console_is_usable() returns false when the new suspended flag is set for that console. Signed-off-by: John Ogness Reviewed-by: Sergey Senozhatsky Reviewed-by: Petr Mladek Signed-off-by: Petr Mladek Link: https://lore.kernel.org/r/20230717194607.145135-7-john.ogness@linutronix.de --- include/linux/console.h | 3 ++ kernel/printk/printk.c | 74 ++++++++++++++++++++++++----------------- 2 files changed, 47 insertions(+), 30 deletions(-) diff --git a/include/linux/console.h b/include/linux/console.h index d3195664baa5a..7de11c763eb35 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -154,6 +154,8 @@ static inline int con_debug_leave(void) * receiving the printk spam for obvious reasons. * @CON_EXTENDED: The console supports the extended output format of * /dev/kmesg which requires a larger output buffer. + * @CON_SUSPENDED: Indicates if a console is suspended. If true, the + * printing callbacks must not be called. */ enum cons_flags { CON_PRINTBUFFER = BIT(0), @@ -163,6 +165,7 @@ enum cons_flags { CON_ANYTIME = BIT(4), CON_BRL = BIT(5), CON_EXTENDED = BIT(6), + CON_SUSPENDED = BIT(7), }; /** diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 6e853a1441a7c..efe5774779137 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -86,7 +86,7 @@ EXPORT_SYMBOL(oops_in_progress); static DEFINE_MUTEX(console_mutex); /* - * console_sem protects updates to console->seq and console_suspended, + * console_sem protects updates to console->seq * and also provides serialization for console printing. */ static DEFINE_SEMAPHORE(console_sem); @@ -359,7 +359,7 @@ static bool panic_in_progress(void) * paths in the console code where we end up in places I want * locked without the console semaphore held). */ -static int console_locked, console_suspended; +static int console_locked; /* * Array of consoles built from command line options (console=) @@ -2549,22 +2549,46 @@ MODULE_PARM_DESC(console_no_auto_verbose, "Disable console loglevel raise to hig */ void suspend_console(void) { + struct console *con; + if (!console_suspend_enabled) return; pr_info("Suspending console(s) (use no_console_suspend to debug)\n"); pr_flush(1000, true); - console_lock(); - console_suspended = 1; - up_console_sem(); + + console_list_lock(); + for_each_console(con) + console_srcu_write_flags(con, con->flags | CON_SUSPENDED); + console_list_unlock(); + + /* + * Ensure that all SRCU list walks have completed. All printing + * contexts must be able to see that they are suspended so that it + * is guaranteed that all printing has stopped when this function + * completes. + */ + synchronize_srcu(&console_srcu); } void resume_console(void) { + struct console *con; + if (!console_suspend_enabled) return; - down_console_sem(); - console_suspended = 0; - console_unlock(); + + console_list_lock(); + for_each_console(con) + console_srcu_write_flags(con, con->flags & ~CON_SUSPENDED); + console_list_unlock(); + + /* + * Ensure that all SRCU list walks have completed. All printing + * contexts must be able to see they are no longer suspended so + * that they are guaranteed to wake up and resume printing. + */ + synchronize_srcu(&console_srcu); + pr_flush(1000, true); } @@ -2623,8 +2647,6 @@ void console_lock(void) msleep(1000); down_console_sem(); - if (console_suspended) - return; console_locked = 1; console_may_schedule = 1; } @@ -2645,10 +2667,6 @@ int console_trylock(void) return 0; if (down_trylock_console_sem()) return 0; - if (console_suspended) { - up_console_sem(); - return 0; - } console_locked = 1; console_may_schedule = 0; return 1; @@ -2674,6 +2692,9 @@ static inline bool console_is_usable(struct console *con) if (!(flags & CON_ENABLED)) return false; + if ((flags & CON_SUSPENDED)) + return false; + if (!con->write) return false; @@ -2992,11 +3013,6 @@ void console_unlock(void) bool flushed; u64 next_seq; - if (console_suspended) { - up_console_sem(); - return; - } - /* * Console drivers are called with interrupts disabled, so * @console_may_schedule should be cleared before; however, we may @@ -3726,8 +3742,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre /* * Hold the console_lock to guarantee safe access to - * console->seq and to prevent changes to @console_suspended - * until all consoles have been processed. + * console->seq. */ console_lock(); @@ -3735,6 +3750,11 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre for_each_console_srcu(c) { if (con && con != c) continue; + /* + * If consoles are not usable, it cannot be expected + * that they make forward progress, so only increment + * @diff for usable consoles. + */ if (!console_is_usable(c)) continue; printk_seq = c->seq; @@ -3743,18 +3763,12 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre } console_srcu_read_unlock(cookie); - /* - * If consoles are suspended, it cannot be expected that they - * make forward progress, so timeout immediately. @diff is - * still used to return a valid flush status. - */ - if (console_suspended) - remaining = 0; - else if (diff != last_diff && reset_on_progress) + if (diff != last_diff && reset_on_progress) remaining = timeout_ms; console_unlock(); + /* Note: @diff is 0 if there are no usable consoles. */ if (diff == 0 || remaining == 0) break; @@ -3788,7 +3802,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre * printer has been seen to make some forward progress. * * Context: Process context. May sleep while acquiring console lock. - * Return: true if all enabled printers are caught up. + * Return: true if all usable printers are caught up. */ static bool pr_flush(int timeout_ms, bool reset_on_progress) { -- GitLab From 132a90d1527fedba2d95085c951ccf00dbbebe41 Mon Sep 17 00:00:00 2001 From: John Ogness Date: Mon, 17 Jul 2023 21:52:07 +0206 Subject: [PATCH 0272/3445] printk: Rename abandon_console_lock_in_panic() to other_cpu_in_panic() Currently abandon_console_lock_in_panic() is only used to determine if the current CPU should immediately release the console lock because another CPU is in panic. However, later this function will be used by the CPU to immediately release other resources in this situation. Rename the function to other_cpu_in_panic(), which is a better description and does not assume it is related to the console lock. Signed-off-by: John Ogness Reviewed-by: Sergey Senozhatsky Reviewed-by: Petr Mladek Signed-off-by: Petr Mladek Link: https://lore.kernel.org/r/20230717194607.145135-8-john.ogness@linutronix.de --- kernel/printk/internal.h | 2 ++ kernel/printk/printk.c | 15 ++++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h index 2a17704136f1d..7d4979d5c3ce6 100644 --- a/kernel/printk/internal.h +++ b/kernel/printk/internal.h @@ -103,3 +103,5 @@ struct printk_message { u64 seq; unsigned long dropped; }; + +bool other_cpu_in_panic(void); diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index efe5774779137..8787d3a721146 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2612,11 +2612,12 @@ static int console_cpu_notify(unsigned int cpu) } /* - * Return true when this CPU should unlock console_sem without pushing all - * messages to the console. This reduces the chance that the console is - * locked when the panic CPU tries to use it. + * Return true if a panic is in progress on a remote CPU. + * + * On true, the local CPU should immediately release any printing resources + * that may be needed by the panic CPU. */ -static bool abandon_console_lock_in_panic(void) +bool other_cpu_in_panic(void) { if (!panic_in_progress()) return false; @@ -2643,7 +2644,7 @@ void console_lock(void) might_sleep(); /* On panic, the console_lock must be left to the panic cpu. */ - while (abandon_console_lock_in_panic()) + while (other_cpu_in_panic()) msleep(1000); down_console_sem(); @@ -2663,7 +2664,7 @@ EXPORT_SYMBOL(console_lock); int console_trylock(void) { /* On panic, the console_lock must be left to the panic cpu. */ - if (abandon_console_lock_in_panic()) + if (other_cpu_in_panic()) return 0; if (down_trylock_console_sem()) return 0; @@ -2978,7 +2979,7 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove any_progress = true; /* Allow panic_cpu to take over the consoles safely. */ - if (abandon_console_lock_in_panic()) + if (other_cpu_in_panic()) goto abandon; if (do_cond_resched) -- GitLab From 3f6a74bd628278e6eab4220449702a388aea7595 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 19 Jul 2023 12:20:11 -0300 Subject: [PATCH 0273/3445] perf evsel: Free evsel->filter on the destructor Noticed with: make EXTRA_CFLAGS="-fsanitize=address" BUILD_BPF_SKEL=1 CORESIGHT=1 O=/tmp/build/perf-tools-next -C tools/perf install-bin Direct leak of 45 byte(s) in 1 object(s) allocated from: #0 0x7f213f87243b in strdup (/lib64/libasan.so.8+0x7243b) #1 0x63d15f in evsel__set_filter util/evsel.c:1371 #2 0x63d15f in evsel__append_filter util/evsel.c:1387 #3 0x63d15f in evsel__append_tp_filter util/evsel.c:1400 #4 0x62cd52 in evlist__append_tp_filter util/evlist.c:1145 #5 0x62cd52 in evlist__append_tp_filter_pids util/evlist.c:1196 #6 0x541e49 in trace__set_filter_loop_pids /home/acme/git/perf-tools/tools/perf/builtin-trace.c:3646 #7 0x541e49 in trace__set_filter_pids /home/acme/git/perf-tools/tools/perf/builtin-trace.c:3670 #8 0x541e49 in trace__run /home/acme/git/perf-tools/tools/perf/builtin-trace.c:3970 #9 0x541e49 in cmd_trace /home/acme/git/perf-tools/tools/perf/builtin-trace.c:5141 #10 0x5ef1a2 in run_builtin /home/acme/git/perf-tools/tools/perf/perf.c:323 #11 0x4196da in handle_internal_command /home/acme/git/perf-tools/tools/perf/perf.c:377 #12 0x4196da in run_argv /home/acme/git/perf-tools/tools/perf/perf.c:421 #13 0x4196da in main /home/acme/git/perf-tools/tools/perf/perf.c:537 #14 0x7f213e84a50f in __libc_start_call_main (/lib64/libc.so.6+0x2750f) Free it on evsel__exit(). Acked-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/20230719202951.534582-2-acme@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 762e2b2634a55..e41bc4d9925f6 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1474,6 +1474,7 @@ void evsel__exit(struct evsel *evsel) perf_thread_map__put(evsel->core.threads); zfree(&evsel->group_name); zfree(&evsel->name); + zfree(&evsel->filter); zfree(&evsel->pmu_name); zfree(&evsel->group_pmu_name); zfree(&evsel->unit); -- GitLab From 04cb4fc4d40a5bf1f9d116bc77e69791451f9fcc Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 19 Jul 2023 15:23:52 -0300 Subject: [PATCH 0274/3445] perf thread: Allow tools to register a thread->priv destructor So that when thread__delete() runs it can be called and free stuff tools stashed into thread->priv, like 'perf trace' does and will use this new facility to plug some leaks. Added an assert(thread__priv_destructor == NULL) as suggested in Ian's review. Acked-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/CAP-5=fV3Er=Ek8=iE=bSGbEBmM56_PJffMWot1g_5Bh8B5hO7A@mail.gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/thread.c | 13 +++++++++++++ tools/perf/util/thread.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 0b166404c5c36..fe5e6991ae4b4 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -80,6 +80,15 @@ err_thread: return NULL; } +static void (*thread__priv_destructor)(void *priv); + +void thread__set_priv_destructor(void (*destructor)(void *priv)) +{ + assert(thread__priv_destructor == NULL); + + thread__priv_destructor = destructor; +} + void thread__delete(struct thread *thread) { struct namespaces *namespaces, *tmp_namespaces; @@ -112,6 +121,10 @@ void thread__delete(struct thread *thread) exit_rwsem(thread__namespaces_lock(thread)); exit_rwsem(thread__comm_lock(thread)); thread__free_stitch_list(thread); + + if (thread__priv_destructor) + thread__priv_destructor(thread__priv(thread)); + RC_CHK_FREE(thread); } diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 9068a21ce0fa1..e79225a0ea46b 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -71,6 +71,8 @@ struct thread *thread__new(pid_t pid, pid_t tid); int thread__init_maps(struct thread *thread, struct machine *machine); void thread__delete(struct thread *thread); +void thread__set_priv_destructor(void (*destructor)(void *priv)); + struct thread *thread__get(struct thread *thread); void thread__put(struct thread *thread); -- GitLab From 9de251cb501f834aeb13e87598d1f78588964101 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 19 Jul 2023 15:26:23 -0300 Subject: [PATCH 0275/3445] perf trace: Register a thread priv destructor To plug these leaks detected with: $ make EXTRA_CFLAGS="-fsanitize=address" BUILD_BPF_SKEL=1 CORESIGHT=1 O=/tmp/build/perf-tools-next -C tools/perf install-bin ================================================================= ==473890==ERROR: LeakSanitizer: detected memory leaks Direct leak of 112 byte(s) in 1 object(s) allocated from: #0 0x7fdf19aba097 in calloc (/lib64/libasan.so.8+0xba097) #1 0x987836 in zalloc (/home/acme/bin/perf+0x987836) #2 0x5367ae in thread_trace__new /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:1289 #3 0x5367ae in thread__trace /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:1307 #4 0x5367ae in trace__sys_exit /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:2468 #5 0x52bf34 in trace__handle_event /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:3177 #6 0x52bf34 in __trace__deliver_event /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:3685 #7 0x542927 in trace__deliver_event /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:3712 #8 0x542927 in trace__run /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:4055 #9 0x542927 in cmd_trace /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:5141 #10 0x5ef1a2 in run_builtin /home/acme/git/perf-tools-next/tools/perf/perf.c:323 #11 0x4196da in handle_internal_command /home/acme/git/perf-tools-next/tools/perf/perf.c:377 #12 0x4196da in run_argv /home/acme/git/perf-tools-next/tools/perf/perf.c:421 #13 0x4196da in main /home/acme/git/perf-tools-next/tools/perf/perf.c:537 #14 0x7fdf18a4a50f in __libc_start_call_main (/lib64/libc.so.6+0x2750f) Direct leak of 2048 byte(s) in 1 object(s) allocated from: #0 0x7f788fcba6af in __interceptor_malloc (/lib64/libasan.so.8+0xba6af) #1 0x5337c0 in trace__sys_enter /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:2342 #2 0x52bfb4 in trace__handle_event /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:3191 #3 0x52bfb4 in __trace__deliver_event /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:3699 #4 0x542883 in trace__deliver_event /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:3726 #5 0x542883 in trace__run /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:4069 #6 0x542883 in cmd_trace /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:5155 #7 0x5ef232 in run_builtin /home/acme/git/perf-tools-next/tools/perf/perf.c:323 #8 0x4196da in handle_internal_command /home/acme/git/perf-tools-next/tools/perf/perf.c:377 #9 0x4196da in run_argv /home/acme/git/perf-tools-next/tools/perf/perf.c:421 #10 0x4196da in main /home/acme/git/perf-tools-next/tools/perf/perf.c:537 #11 0x7f788ec4a50f in __libc_start_call_main (/lib64/libc.so.6+0x2750f) Indirect leak of 48 byte(s) in 1 object(s) allocated from: #0 0x7fdf19aba6af in __interceptor_malloc (/lib64/libasan.so.8+0xba6af) #1 0x77b335 in intlist__new util/intlist.c:116 #2 0x5367fd in thread_trace__new /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:1293 #3 0x5367fd in thread__trace /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:1307 #4 0x5367fd in trace__sys_exit /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:2468 #5 0x52bf34 in trace__handle_event /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:3177 #6 0x52bf34 in __trace__deliver_event /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:3685 #7 0x542927 in trace__deliver_event /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:3712 #8 0x542927 in trace__run /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:4055 #9 0x542927 in cmd_trace /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:5141 #10 0x5ef1a2 in run_builtin /home/acme/git/perf-tools-next/tools/perf/perf.c:323 #11 0x4196da in handle_internal_command /home/acme/git/perf-tools-next/tools/perf/perf.c:377 #12 0x4196da in run_argv /home/acme/git/perf-tools-next/tools/perf/perf.c:421 #13 0x4196da in main /home/acme/git/perf-tools-next/tools/perf/perf.c:537 #14 0x7fdf18a4a50f in __libc_start_call_main (/lib64/libc.so.6+0x2750f) Acked-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/20230719202951.534582-4-acme@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 6e73d0e957152..b7cbe4bcd136b 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1296,6 +1296,19 @@ static struct thread_trace *thread_trace__new(void) return ttrace; } +static void thread_trace__delete(void *pttrace) +{ + struct thread_trace *ttrace = pttrace; + + if (!ttrace) + return; + + intlist__delete(ttrace->syscall_stats); + ttrace->syscall_stats = NULL; + zfree(&ttrace->entry_str); + free(ttrace); +} + static struct thread_trace *thread__trace(struct thread *thread, FILE *fp) { struct thread_trace *ttrace; @@ -1635,6 +1648,8 @@ static int trace__symbols_init(struct trace *trace, struct evlist *evlist) if (trace->host == NULL) return -ENOMEM; + thread__set_priv_destructor(thread_trace__delete); + err = trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr); if (err < 0) goto out; -- GitLab From 7962ef13651a9163f07b530607392ea123482e8a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 19 Jul 2023 15:37:14 -0300 Subject: [PATCH 0276/3445] perf trace: Really free the evsel->priv area In 3cb4d5e00e037c70 ("perf trace: Free syscall tp fields in evsel->priv") it only was freeing if strcmp(evsel->tp_format->system, "syscalls") returned zero, while the corresponding initialization of evsel->priv was being performed if it was _not_ zero, i.e. if the tp system wasn't 'syscalls'. Just stop looking for that and free it if evsel->priv was set, which should be equivalent. Also use the pre-existing evsel_trace__delete() function. This resolves these leaks, detected with: $ make EXTRA_CFLAGS="-fsanitize=address" BUILD_BPF_SKEL=1 CORESIGHT=1 O=/tmp/build/perf-tools-next -C tools/perf install-bin ================================================================= ==481565==ERROR: LeakSanitizer: detected memory leaks Direct leak of 40 byte(s) in 1 object(s) allocated from: #0 0x7f7343cba097 in calloc (/lib64/libasan.so.8+0xba097) #1 0x987966 in zalloc (/home/acme/bin/perf+0x987966) #2 0x52f9b9 in evsel_trace__new /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:307 #3 0x52f9b9 in evsel__syscall_tp /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:333 #4 0x52f9b9 in evsel__init_raw_syscall_tp /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:458 #5 0x52f9b9 in perf_evsel__raw_syscall_newtp /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:480 #6 0x540e8b in trace__add_syscall_newtp /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:3212 #7 0x540e8b in trace__run /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:3891 #8 0x540e8b in cmd_trace /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:5156 #9 0x5ef262 in run_builtin /home/acme/git/perf-tools-next/tools/perf/perf.c:323 #10 0x4196da in handle_internal_command /home/acme/git/perf-tools-next/tools/perf/perf.c:377 #11 0x4196da in run_argv /home/acme/git/perf-tools-next/tools/perf/perf.c:421 #12 0x4196da in main /home/acme/git/perf-tools-next/tools/perf/perf.c:537 #13 0x7f7342c4a50f in __libc_start_call_main (/lib64/libc.so.6+0x2750f) Direct leak of 40 byte(s) in 1 object(s) allocated from: #0 0x7f7343cba097 in calloc (/lib64/libasan.so.8+0xba097) #1 0x987966 in zalloc (/home/acme/bin/perf+0x987966) #2 0x52f9b9 in evsel_trace__new /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:307 #3 0x52f9b9 in evsel__syscall_tp /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:333 #4 0x52f9b9 in evsel__init_raw_syscall_tp /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:458 #5 0x52f9b9 in perf_evsel__raw_syscall_newtp /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:480 #6 0x540dd1 in trace__add_syscall_newtp /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:3205 #7 0x540dd1 in trace__run /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:3891 #8 0x540dd1 in cmd_trace /home/acme/git/perf-tools-next/tools/perf/builtin-trace.c:5156 #9 0x5ef262 in run_builtin /home/acme/git/perf-tools-next/tools/perf/perf.c:323 #10 0x4196da in handle_internal_command /home/acme/git/perf-tools-next/tools/perf/perf.c:377 #11 0x4196da in run_argv /home/acme/git/perf-tools-next/tools/perf/perf.c:421 #12 0x4196da in main /home/acme/git/perf-tools-next/tools/perf/perf.c:537 #13 0x7f7342c4a50f in __libc_start_call_main (/lib64/libc.so.6+0x2750f) SUMMARY: AddressSanitizer: 80 byte(s) leaked in 2 allocation(s). [root@quaco ~]# With this we plug all leaks with "perf trace sleep 1". Fixes: 3cb4d5e00e037c70 ("perf trace: Free syscall tp fields in evsel->priv") Acked-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Cc: Riccardo Mancini Link: https://lore.kernel.org/lkml/20230719202951.534582-5-acme@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index b7cbe4bcd136b..56651d666480c 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -3151,13 +3151,8 @@ static void evlist__free_syscall_tp_fields(struct evlist *evlist) struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { - struct evsel_trace *et = evsel->priv; - - if (!et || !evsel->tp_format || strcmp(evsel->tp_format->system, "syscalls")) - continue; - - zfree(&et->fmt); - free(et); + evsel_trace__delete(evsel->priv); + evsel->priv = NULL; } } -- GitLab From fcca1faf11b47011770c361a1dfc36ed83905148 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 19 Jul 2023 16:49:02 -0300 Subject: [PATCH 0277/3445] perf trace: Free thread_trace->files table The fd->pathname table that is kept in 'struct thread_trace' and thus in thread->priv must be freed when a thread is deleted. This was also detected using -fsanitize=address. Acked-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/20230719202951.534582-6-acme@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 56651d666480c..7ece2521efb69 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1296,6 +1296,8 @@ static struct thread_trace *thread_trace__new(void) return ttrace; } +static void thread_trace__free_files(struct thread_trace *ttrace); + static void thread_trace__delete(void *pttrace) { struct thread_trace *ttrace = pttrace; @@ -1305,6 +1307,7 @@ static void thread_trace__delete(void *pttrace) intlist__delete(ttrace->syscall_stats); ttrace->syscall_stats = NULL; + thread_trace__free_files(ttrace); zfree(&ttrace->entry_str); free(ttrace); } @@ -1346,6 +1349,17 @@ void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg, static const size_t trace__entry_str_size = 2048; +static void thread_trace__free_files(struct thread_trace *ttrace) +{ + for (int i = 0; i < ttrace->files.max; ++i) { + struct file *file = ttrace->files.table + i; + zfree(&file->pathname); + } + + zfree(&ttrace->files.table); + ttrace->files.max = -1; +} + static struct file *thread_trace__files_entry(struct thread_trace *ttrace, int fd) { if (fd < 0) -- GitLab From faa4e0da1cbab97aa18bb6562ab32d9f0fc32e82 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 19 Jul 2023 16:53:01 -0300 Subject: [PATCH 0278/3445] MAINTAINERS: Add git information for perf-tools and perf-tools-next trees/branches Now the perf tools development is done on these trees/branches: git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools.git perf-tools git git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git perf-tools-next For a while I'll continue mirroring what is these to the same branches in my git tree. Suggested-by: John Garry Acked-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/lkml/CAP-5=fVGOP6-k=BTRd_bn=N0HVy+1ShpdW5rk5ND0ZGhm_fQkg@mail.gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index aee340630ecae..e351cfc7cd41c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16629,6 +16629,8 @@ L: linux-kernel@vger.kernel.org S: Supported W: https://perf.wiki.kernel.org/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git perf/core +T: git git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools.git perf-tools +T: git git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git perf-tools-next F: arch/*/events/* F: arch/*/events/*/* F: arch/*/include/asm/perf_event.h -- GitLab From 2df270716447a1024a6c955eed8fa579333dca85 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 2 Jun 2023 15:18:27 -0300 Subject: [PATCH 0279/3445] perf bench uprobe: Add benchmark to test uprobe overhead This just adds the initial "workload", a call to libc's usleep(1000us) function: $ perf stat --null perf bench uprobe all # Running uprobe/baseline benchmark... # Executed 1000 usleep(1000) calls Total time: 1053533 usecs 1053.533 usecs/op Performance counter stats for 'perf bench uprobe all': 1.061042896 seconds time elapsed 0.001079000 seconds user 0.006499000 seconds sys $ More entries will be added using a BPF skel to add various uprobes to the usleep() function. Acked-by: Ian Rogers Cc: Adrian Hunter Cc: Andre Fredette Cc: Clark Williams Cc: Dave Tucker Cc: Derek Barbosa Cc: Jiri Olsa Cc: Masami Hiramatsu (Google) Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/20230719204910.539044-2-acme@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-bench.txt | 3 + tools/perf/bench/Build | 1 + tools/perf/bench/bench.h | 1 + tools/perf/bench/uprobe.c | 80 +++++++++++++++++++++++++ tools/perf/builtin-bench.c | 6 ++ 5 files changed, 91 insertions(+) create mode 100644 tools/perf/bench/uprobe.c diff --git a/tools/perf/Documentation/perf-bench.txt b/tools/perf/Documentation/perf-bench.txt index f04f0eaded985..ca5789625cd2b 100644 --- a/tools/perf/Documentation/perf-bench.txt +++ b/tools/perf/Documentation/perf-bench.txt @@ -67,6 +67,9 @@ SUBSYSTEM 'internals':: Benchmark internal perf functionality. +'uprobe':: + Benchmark overhead of uprobe + BPF. + 'all':: All benchmark subsystems. diff --git a/tools/perf/bench/Build b/tools/perf/bench/Build index 0f158dc8139bb..47412d47dccfe 100644 --- a/tools/perf/bench/Build +++ b/tools/perf/bench/Build @@ -16,6 +16,7 @@ perf-y += inject-buildid.o perf-y += evlist-open-close.o perf-y += breakpoint.o perf-y += pmu-scan.o +perf-y += uprobe.o perf-$(CONFIG_X86_64) += mem-memcpy-x86-64-asm.o perf-$(CONFIG_X86_64) += mem-memset-x86-64-asm.o diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h index 0d2b659762123..201311f75c964 100644 --- a/tools/perf/bench/bench.h +++ b/tools/perf/bench/bench.h @@ -42,6 +42,7 @@ int bench_inject_build_id(int argc, const char **argv); int bench_evlist_open_close(int argc, const char **argv); int bench_breakpoint_thread(int argc, const char **argv); int bench_breakpoint_enable(int argc, const char **argv); +int bench_uprobe_baseline(int argc, const char **argv); int bench_pmu_scan(int argc, const char **argv); #define BENCH_FORMAT_DEFAULT_STR "default" diff --git a/tools/perf/bench/uprobe.c b/tools/perf/bench/uprobe.c new file mode 100644 index 0000000000000..707174220a767 --- /dev/null +++ b/tools/perf/bench/uprobe.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * uprobe.c + * + * uprobe benchmarks + * + * Copyright (C) 2023, Red Hat Inc, Arnaldo Carvalho de Melo + */ +#include "../perf.h" +#include "../util/util.h" +#include +#include "../builtin.h" +#include "bench.h" +#include + +#include +#include +#include +#include +#include +#include +#include + +#define LOOPS_DEFAULT 1000 +static int loops = LOOPS_DEFAULT; + +static const struct option options[] = { + OPT_INTEGER('l', "loop", &loops, "Specify number of loops"), + OPT_END() +}; + +static const char * const bench_uprobe_usage[] = { + "perf bench uprobe ", + NULL +}; + +static int bench_uprobe(int argc, const char **argv) +{ + const char *name = "usleep(1000)", *unit = "usec"; + struct timespec start, end; + u64 diff; + int i; + + argc = parse_options(argc, argv, options, bench_uprobe_usage, 0); + + clock_gettime(CLOCK_REALTIME, &start); + + for (i = 0; i < loops; i++) { + usleep(USEC_PER_MSEC); + } + + clock_gettime(CLOCK_REALTIME, &end); + + diff = end.tv_sec * NSEC_PER_SEC + end.tv_nsec - (start.tv_sec * NSEC_PER_SEC + start.tv_nsec); + diff /= NSEC_PER_USEC; + + switch (bench_format) { + case BENCH_FORMAT_DEFAULT: + printf("# Executed %'d %s calls\n", loops, name); + printf(" %14s: %'" PRIu64 " %ss\n\n", "Total time", diff, unit); + printf(" %'.3f %ss/op\n", (double)diff / (double)loops, unit); + break; + + case BENCH_FORMAT_SIMPLE: + printf("%" PRIu64 "\n", diff); + break; + + default: + /* reaching here is something of a disaster */ + fprintf(stderr, "Unknown format:%d\n", bench_format); + exit(1); + } + + return 0; +} + +int bench_uprobe_baseline(int argc, const char **argv) +{ + return bench_uprobe(argc, argv); +} diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c index db435b791a09b..09637aee83413 100644 --- a/tools/perf/builtin-bench.c +++ b/tools/perf/builtin-bench.c @@ -104,6 +104,11 @@ static struct bench breakpoint_benchmarks[] = { { NULL, NULL, NULL }, }; +static struct bench uprobe_benchmarks[] = { + { "baseline", "Baseline libc usleep(1000) call", bench_uprobe_baseline, }, + { NULL, NULL, NULL }, +}; + struct collection { const char *name; const char *summary; @@ -123,6 +128,7 @@ static struct collection collections[] = { #endif { "internals", "Perf-internals benchmarks", internals_benchmarks }, { "breakpoint", "Breakpoint benchmarks", breakpoint_benchmarks }, + { "uprobe", "uprobe benchmarks", uprobe_benchmarks }, { "all", "All benchmarks", NULL }, { NULL, NULL, NULL } }; -- GitLab From dded6f615b854740461be63672fa05158875ffaa Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 5 Jul 2023 08:45:12 -0300 Subject: [PATCH 0280/3445] perf bench uprobe: Print diff to baseline This is just prep work to show the diff to the unmodified workload. Acked-by: Ian Rogers Cc: Adrian Hunter Cc: Andre Fredette Cc: Clark Williams Cc: Dave Tucker Cc: Derek Barbosa Cc: Jiri Olsa Cc: Masami Hiramatsu (Google) Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/20230719204910.539044-3-acme@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/uprobe.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/tools/perf/bench/uprobe.c b/tools/perf/bench/uprobe.c index 707174220a767..60e7c43298d8c 100644 --- a/tools/perf/bench/uprobe.c +++ b/tools/perf/bench/uprobe.c @@ -34,6 +34,29 @@ static const char * const bench_uprobe_usage[] = { NULL }; +static int bench_uprobe_format__default_fprintf(const char *name, const char *unit, u64 diff, FILE *fp) +{ + static u64 baseline; + s64 diff_to_baseline = diff - baseline; + int printed = fprintf(fp, "# Executed %'d %s calls\n", loops, name); + + printed += fprintf(fp, " %14s: %'" PRIu64 " %ss", "Total time", diff, unit); + + if (baseline) + printed += fprintf(fp, " %s%'" PRId64 " to baseline", diff_to_baseline > 0 ? "+" : "", diff_to_baseline); + + printed += fprintf(fp, "\n\n %'.3f %ss/op", (double)diff / (double)loops, unit); + + if (baseline) + printed += fprintf(fp, " %'.3f %ss/op to baseline", (double)diff_to_baseline / (double)loops, unit); + else + baseline = diff; + + fputc('\n', fp); + + return printed + 1; +} + static int bench_uprobe(int argc, const char **argv) { const char *name = "usleep(1000)", *unit = "usec"; @@ -56,9 +79,7 @@ static int bench_uprobe(int argc, const char **argv) switch (bench_format) { case BENCH_FORMAT_DEFAULT: - printf("# Executed %'d %s calls\n", loops, name); - printf(" %14s: %'" PRIu64 " %ss\n\n", "Total time", diff, unit); - printf(" %'.3f %ss/op\n", (double)diff / (double)loops, unit); + bench_uprobe_format__default_fprintf(name, unit, diff, stdout); break; case BENCH_FORMAT_SIMPLE: -- GitLab From 54d811023b5f99e658511b577b16a6d7014d162c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 5 Jul 2023 08:49:40 -0300 Subject: [PATCH 0281/3445] perf bench uprobe: Show diff to previous Will be useful to show the incremental overhead as we do more stuff in the BPF program attached to the uprobes. Acked-by: Ian Rogers Cc: Adrian Hunter Cc: Andre Fredette Cc: Clark Williams Cc: Dave Tucker Cc: Derek Barbosa Cc: Jiri Olsa Cc: Masami Hiramatsu (Google) Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/20230719204910.539044-4-acme@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/uprobe.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/tools/perf/bench/uprobe.c b/tools/perf/bench/uprobe.c index 60e7c43298d8c..a90e09f791c54 100644 --- a/tools/perf/bench/uprobe.c +++ b/tools/perf/bench/uprobe.c @@ -36,24 +36,35 @@ static const char * const bench_uprobe_usage[] = { static int bench_uprobe_format__default_fprintf(const char *name, const char *unit, u64 diff, FILE *fp) { - static u64 baseline; - s64 diff_to_baseline = diff - baseline; + static u64 baseline, previous; + s64 diff_to_baseline = diff - baseline, + diff_to_previous = diff - previous; int printed = fprintf(fp, "# Executed %'d %s calls\n", loops, name); printed += fprintf(fp, " %14s: %'" PRIu64 " %ss", "Total time", diff, unit); - if (baseline) + if (baseline) { printed += fprintf(fp, " %s%'" PRId64 " to baseline", diff_to_baseline > 0 ? "+" : "", diff_to_baseline); + if (previous != baseline) + fprintf(stdout, " %s%'" PRId64 " to previous", diff_to_previous > 0 ? "+" : "", diff_to_previous); + } + printed += fprintf(fp, "\n\n %'.3f %ss/op", (double)diff / (double)loops, unit); - if (baseline) + if (baseline) { printed += fprintf(fp, " %'.3f %ss/op to baseline", (double)diff_to_baseline / (double)loops, unit); - else + + if (previous != baseline) + printed += fprintf(fp, " %'.3f %ss/op to previous", (double)diff_to_previous / (double)loops, unit); + } else { baseline = diff; + } fputc('\n', fp); + previous = diff; + return printed + 1; } -- GitLab From 6af5e4cf3a6521d23ca53df5001319babefdffbf Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 2 Jun 2023 17:42:47 -0300 Subject: [PATCH 0282/3445] perf bench uprobe empty: Add entry attaching an empty BPF program Using libbpf and a BPF skel: # perf bench uprobe all # Running uprobe/baseline benchmark... # Executed 1,000 usleep(1000) calls Total time: 1,055,618 usecs 1,055.618 usecs/op # Running uprobe/empty benchmark... # Executed 1,000 usleep(1000) calls Total time: 1,057,146 usecs +1,528 to baseline 1,057.146 usecs/op # Acked-by: Ian Rogers Cc: Adrian Hunter Cc: Andre Fredette Cc: Clark Williams Cc: Dave Tucker Cc: Derek Barbosa Cc: Jiri Olsa Cc: Masami Hiramatsu (Google) Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/20230719204910.539044-5-acme@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 1 + tools/perf/bench/bench.h | 1 + tools/perf/bench/uprobe.c | 75 ++++++++++++++++++++- tools/perf/builtin-bench.c | 3 +- tools/perf/util/bpf_skel/bench_uprobe.bpf.c | 12 ++++ 5 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 tools/perf/util/bpf_skel/bench_uprobe.bpf.c diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 097316ef38e6a..a44d16ec11ee5 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -1057,6 +1057,7 @@ SKELETONS += $(SKEL_OUT)/bperf_leader.skel.h $(SKEL_OUT)/bperf_follower.skel.h SKELETONS += $(SKEL_OUT)/bperf_cgroup.skel.h $(SKEL_OUT)/func_latency.skel.h SKELETONS += $(SKEL_OUT)/off_cpu.skel.h $(SKEL_OUT)/lock_contention.skel.h SKELETONS += $(SKEL_OUT)/kwork_trace.skel.h $(SKEL_OUT)/sample_filter.skel.h +SKELETONS += $(SKEL_OUT)/bench_uprobe.skel.h $(SKEL_TMP_OUT) $(LIBAPI_OUTPUT) $(LIBBPF_OUTPUT) $(LIBPERF_OUTPUT) $(LIBSUBCMD_OUTPUT) $(LIBSYMBOL_OUTPUT): $(Q)$(MKDIR) -p $@ diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h index 201311f75c964..daf4850b441cf 100644 --- a/tools/perf/bench/bench.h +++ b/tools/perf/bench/bench.h @@ -43,6 +43,7 @@ int bench_evlist_open_close(int argc, const char **argv); int bench_breakpoint_thread(int argc, const char **argv); int bench_breakpoint_enable(int argc, const char **argv); int bench_uprobe_baseline(int argc, const char **argv); +int bench_uprobe_empty(int argc, const char **argv); int bench_pmu_scan(int argc, const char **argv); #define BENCH_FORMAT_DEFAULT_STR "default" diff --git a/tools/perf/bench/uprobe.c b/tools/perf/bench/uprobe.c index a90e09f791c54..dfb90038a4f7a 100644 --- a/tools/perf/bench/uprobe.c +++ b/tools/perf/bench/uprobe.c @@ -24,6 +24,11 @@ #define LOOPS_DEFAULT 1000 static int loops = LOOPS_DEFAULT; +enum bench_uprobe { + BENCH_UPROBE__BASELINE, + BENCH_UPROBE__EMPTY, +}; + static const struct option options[] = { OPT_INTEGER('l', "loop", &loops, "Specify number of loops"), OPT_END() @@ -34,6 +39,59 @@ static const char * const bench_uprobe_usage[] = { NULL }; +#ifdef HAVE_BPF_SKEL +#include "bpf_skel/bench_uprobe.skel.h" + +struct bench_uprobe_bpf *skel; + +static int bench_uprobe__setup_bpf_skel(void) +{ + DECLARE_LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts); + int err; + + /* Load and verify BPF application */ + skel = bench_uprobe_bpf__open(); + if (!skel) { + fprintf(stderr, "Failed to open and load uprobes bench BPF skeleton\n"); + return -1; + } + + err = bench_uprobe_bpf__load(skel); + if (err) { + fprintf(stderr, "Failed to load and verify BPF skeleton\n"); + goto cleanup; + } + + uprobe_opts.func_name = "usleep"; + skel->links.empty = bpf_program__attach_uprobe_opts(/*prog=*/skel->progs.empty, + /*pid=*/-1, + /*binary_path=*/"/lib64/libc.so.6", + /*func_offset=*/0, + /*opts=*/&uprobe_opts); + if (!skel->links.empty) { + err = -errno; + fprintf(stderr, "Failed to attach bench uprobe: %s\n", strerror(errno)); + goto cleanup; + } + + return err; +cleanup: + bench_uprobe_bpf__destroy(skel); + return err; +} + +static void bench_uprobe__teardown_bpf_skel(void) +{ + if (skel) { + bench_uprobe_bpf__destroy(skel); + skel = NULL; + } +} +#else +static int bench_uprobe__setup_bpf_skel(void) { return 0; } +static void bench_uprobe__teardown_bpf_skel(void) {}; +#endif + static int bench_uprobe_format__default_fprintf(const char *name, const char *unit, u64 diff, FILE *fp) { static u64 baseline, previous; @@ -68,7 +126,7 @@ static int bench_uprobe_format__default_fprintf(const char *name, const char *un return printed + 1; } -static int bench_uprobe(int argc, const char **argv) +static int bench_uprobe(int argc, const char **argv, enum bench_uprobe bench) { const char *name = "usleep(1000)", *unit = "usec"; struct timespec start, end; @@ -77,7 +135,10 @@ static int bench_uprobe(int argc, const char **argv) argc = parse_options(argc, argv, options, bench_uprobe_usage, 0); - clock_gettime(CLOCK_REALTIME, &start); + if (bench != BENCH_UPROBE__BASELINE && bench_uprobe__setup_bpf_skel() < 0) + return 0; + + clock_gettime(CLOCK_REALTIME, &start); for (i = 0; i < loops; i++) { usleep(USEC_PER_MSEC); @@ -103,10 +164,18 @@ static int bench_uprobe(int argc, const char **argv) exit(1); } + if (bench != BENCH_UPROBE__BASELINE) + bench_uprobe__teardown_bpf_skel(); + return 0; } int bench_uprobe_baseline(int argc, const char **argv) { - return bench_uprobe(argc, argv); + return bench_uprobe(argc, argv, BENCH_UPROBE__BASELINE); +} + +int bench_uprobe_empty(int argc, const char **argv) +{ + return bench_uprobe(argc, argv, BENCH_UPROBE__EMPTY); } diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c index 09637aee83413..1021680bbc6d4 100644 --- a/tools/perf/builtin-bench.c +++ b/tools/perf/builtin-bench.c @@ -105,7 +105,8 @@ static struct bench breakpoint_benchmarks[] = { }; static struct bench uprobe_benchmarks[] = { - { "baseline", "Baseline libc usleep(1000) call", bench_uprobe_baseline, }, + { "baseline", "Baseline libc usleep(1000) call", bench_uprobe_baseline, }, + { "empty", "Attach empty BPF prog to uprobe on usleep, system wide", bench_uprobe_empty, }, { NULL, NULL, NULL }, }; diff --git a/tools/perf/util/bpf_skel/bench_uprobe.bpf.c b/tools/perf/util/bpf_skel/bench_uprobe.bpf.c new file mode 100644 index 0000000000000..1365dcc5dddff --- /dev/null +++ b/tools/perf/util/bpf_skel/bench_uprobe.bpf.c @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +// Copyright (c) 2023 Red Hat +#include "vmlinux.h" +#include + +SEC("uprobe") +int BPF_UPROBE(empty) +{ + return 0; +} + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; -- GitLab From 7b47623b8cae8149688c11396bb690bed6936f70 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 2 Jun 2023 17:42:47 -0300 Subject: [PATCH 0283/3445] perf bench uprobe trace_printk: Add entry attaching an BPF program that does a trace_printk [root@five ~]# perf bench uprobe all # Running uprobe/baseline benchmark... # Executed 1,000 usleep(1000) calls Total time: 1,053,963 usecs 1,053.963 usecs/op # Running uprobe/empty benchmark... # Executed 1,000 usleep(1000) calls Total time: 1,056,293 usecs +2,330 to baseline 1,056.293 usecs/op 2.330 usecs/op to baseline # Running uprobe/trace_printk benchmark... # Executed 1,000 usleep(1000) calls Total time: 1,056,977 usecs +3,014 to baseline +684 to previous 1,056.977 usecs/op 3.014 usecs/op to baseline 0.684 usecs/op to previous [root@five ~]# Acked-by: Ian Rogers Cc: Adrian Hunter Cc: Andre Fredette Cc: Clark Williams Cc: Dave Tucker Cc: Derek Barbosa Cc: Jiri Olsa Cc: Masami Hiramatsu (Google) Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/20230719204910.539044-6-acme@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/bench.h | 1 + tools/perf/bench/uprobe.c | 39 +++++++++++++++------ tools/perf/builtin-bench.c | 1 + tools/perf/util/bpf_skel/bench_uprobe.bpf.c | 11 ++++++ 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h index daf4850b441cf..50de4773651f9 100644 --- a/tools/perf/bench/bench.h +++ b/tools/perf/bench/bench.h @@ -44,6 +44,7 @@ int bench_breakpoint_thread(int argc, const char **argv); int bench_breakpoint_enable(int argc, const char **argv); int bench_uprobe_baseline(int argc, const char **argv); int bench_uprobe_empty(int argc, const char **argv); +int bench_uprobe_trace_printk(int argc, const char **argv); int bench_pmu_scan(int argc, const char **argv); #define BENCH_FORMAT_DEFAULT_STR "default" diff --git a/tools/perf/bench/uprobe.c b/tools/perf/bench/uprobe.c index dfb90038a4f7a..914c0817fe8ad 100644 --- a/tools/perf/bench/uprobe.c +++ b/tools/perf/bench/uprobe.c @@ -11,6 +11,7 @@ #include #include "../builtin.h" #include "bench.h" +#include #include #include @@ -27,6 +28,7 @@ static int loops = LOOPS_DEFAULT; enum bench_uprobe { BENCH_UPROBE__BASELINE, BENCH_UPROBE__EMPTY, + BENCH_UPROBE__TRACE_PRINTK, }; static const struct option options[] = { @@ -42,9 +44,21 @@ static const char * const bench_uprobe_usage[] = { #ifdef HAVE_BPF_SKEL #include "bpf_skel/bench_uprobe.skel.h" +#define bench_uprobe__attach_uprobe(prog) \ + skel->links.prog = bpf_program__attach_uprobe_opts(/*prog=*/skel->progs.prog, \ + /*pid=*/-1, \ + /*binary_path=*/"/lib64/libc.so.6", \ + /*func_offset=*/0, \ + /*opts=*/&uprobe_opts); \ + if (!skel->links.prog) { \ + err = -errno; \ + fprintf(stderr, "Failed to attach bench uprobe \"%s\": %s\n", #prog, strerror(errno)); \ + goto cleanup; \ + } + struct bench_uprobe_bpf *skel; -static int bench_uprobe__setup_bpf_skel(void) +static int bench_uprobe__setup_bpf_skel(enum bench_uprobe bench) { DECLARE_LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts); int err; @@ -63,14 +77,12 @@ static int bench_uprobe__setup_bpf_skel(void) } uprobe_opts.func_name = "usleep"; - skel->links.empty = bpf_program__attach_uprobe_opts(/*prog=*/skel->progs.empty, - /*pid=*/-1, - /*binary_path=*/"/lib64/libc.so.6", - /*func_offset=*/0, - /*opts=*/&uprobe_opts); - if (!skel->links.empty) { - err = -errno; - fprintf(stderr, "Failed to attach bench uprobe: %s\n", strerror(errno)); + switch (bench) { + case BENCH_UPROBE__BASELINE: break; + case BENCH_UPROBE__EMPTY: bench_uprobe__attach_uprobe(empty); break; + case BENCH_UPROBE__TRACE_PRINTK: bench_uprobe__attach_uprobe(trace_printk); break; + default: + fprintf(stderr, "Invalid bench: %d\n", bench); goto cleanup; } @@ -88,7 +100,7 @@ static void bench_uprobe__teardown_bpf_skel(void) } } #else -static int bench_uprobe__setup_bpf_skel(void) { return 0; } +static int bench_uprobe__setup_bpf_skel(enum bench_uprobe bench __maybe_unused) { return 0; } static void bench_uprobe__teardown_bpf_skel(void) {}; #endif @@ -135,7 +147,7 @@ static int bench_uprobe(int argc, const char **argv, enum bench_uprobe bench) argc = parse_options(argc, argv, options, bench_uprobe_usage, 0); - if (bench != BENCH_UPROBE__BASELINE && bench_uprobe__setup_bpf_skel() < 0) + if (bench != BENCH_UPROBE__BASELINE && bench_uprobe__setup_bpf_skel(bench) < 0) return 0; clock_gettime(CLOCK_REALTIME, &start); @@ -179,3 +191,8 @@ int bench_uprobe_empty(int argc, const char **argv) { return bench_uprobe(argc, argv, BENCH_UPROBE__EMPTY); } + +int bench_uprobe_trace_printk(int argc, const char **argv) +{ + return bench_uprobe(argc, argv, BENCH_UPROBE__TRACE_PRINTK); +} diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c index 1021680bbc6d4..f60ccafccac25 100644 --- a/tools/perf/builtin-bench.c +++ b/tools/perf/builtin-bench.c @@ -107,6 +107,7 @@ static struct bench breakpoint_benchmarks[] = { static struct bench uprobe_benchmarks[] = { { "baseline", "Baseline libc usleep(1000) call", bench_uprobe_baseline, }, { "empty", "Attach empty BPF prog to uprobe on usleep, system wide", bench_uprobe_empty, }, + { "trace_printk", "Attach trace_printk BPF prog to uprobe on usleep syswide", bench_uprobe_trace_printk, }, { NULL, NULL, NULL }, }; diff --git a/tools/perf/util/bpf_skel/bench_uprobe.bpf.c b/tools/perf/util/bpf_skel/bench_uprobe.bpf.c index 1365dcc5dddff..2c55896bb33c3 100644 --- a/tools/perf/util/bpf_skel/bench_uprobe.bpf.c +++ b/tools/perf/util/bpf_skel/bench_uprobe.bpf.c @@ -3,10 +3,21 @@ #include "vmlinux.h" #include +unsigned int nr_uprobes; + SEC("uprobe") int BPF_UPROBE(empty) { return 0; } +SEC("uprobe") +int BPF_UPROBE(trace_printk) +{ + char fmt[] = "perf bench uprobe %u"; + + bpf_trace_printk(fmt, sizeof(fmt), ++nr_uprobes); + return 0; +} + char LICENSE[] SEC("license") = "Dual BSD/GPL"; -- GitLab From 681f34d52b9647db68cebc5f957ddfff01fb6ba0 Mon Sep 17 00:00:00 2001 From: Lu Hongfei Date: Thu, 6 Jul 2023 17:46:34 +0800 Subject: [PATCH 0284/3445] perf diff: Replaces some ',' as separator with the more usual ';' When wrapping code, use ';' better than using ',' which is more in line with the coding habits of most engineers. Signed-off-by: Lu Hongfei Acked-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: opensource.kernel@vivo.com Link: https://lore.kernel.org/r/20230706094635.1553-1-luhongfei@vivo.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index e8a1b16aa5f83..57d300d8e5700 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -1915,8 +1915,8 @@ static int data_init(int argc, const char **argv) struct perf_data *data = &d->data; data->path = use_default ? defaults[i] : argv[i]; - data->mode = PERF_DATA_MODE_READ, - data->force = force, + data->mode = PERF_DATA_MODE_READ; + data->force = force; d->idx = i; } -- GitLab From 2b6aa9e7927b8e8fe3fd1e0a189d082b0801eacd Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Thu, 20 Jul 2023 14:30:36 -0700 Subject: [PATCH 0285/3445] Input: lm8333 - convert to use devm_* api Use devm_* api to simplify code, this makes it unnecessary to explicitly release resources. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230714080611.81302-1-frank.li@vivo.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/lm8333.c | 44 +++++++++++---------------------- 1 file changed, 14 insertions(+), 30 deletions(-) diff --git a/drivers/input/keyboard/lm8333.c b/drivers/input/keyboard/lm8333.c index c9f05764e36df..1c070c499c85a 100644 --- a/drivers/input/keyboard/lm8333.c +++ b/drivers/input/keyboard/lm8333.c @@ -142,18 +142,18 @@ static int lm8333_probe(struct i2c_client *client) return -EINVAL; } - lm8333 = kzalloc(sizeof(*lm8333), GFP_KERNEL); - input = input_allocate_device(); - if (!lm8333 || !input) { - err = -ENOMEM; - goto free_mem; - } + lm8333 = devm_kzalloc(&client->dev, sizeof(*lm8333), GFP_KERNEL); + if (!lm8333) + return -ENOMEM; + + input = devm_input_allocate_device(&client->dev); + if (!input) + return -ENOMEM; lm8333->client = client; lm8333->input = input; input->name = client->name; - input->dev.parent = &client->dev; input->id.bustype = BUS_I2C; input_set_capability(input, EV_MSC, MSC_SCAN); @@ -162,7 +162,7 @@ static int lm8333_probe(struct i2c_client *client) LM8333_NUM_ROWS, LM8333_NUM_COLS, lm8333->keycodes, input); if (err) - goto free_mem; + return err; if (pdata->debounce_time) { err = lm8333_write8(lm8333, LM8333_DEBOUNCE, @@ -178,34 +178,19 @@ static int lm8333_probe(struct i2c_client *client) dev_warn(&client->dev, "Unable to set active time\n"); } - err = request_threaded_irq(client->irq, NULL, lm8333_irq_thread, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - "lm8333", lm8333); + err = devm_request_threaded_irq(&client->dev, client->irq, + NULL, lm8333_irq_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "lm8333", lm8333); if (err) - goto free_mem; + return err; err = input_register_device(input); if (err) - goto free_irq; + return err; i2c_set_clientdata(client, lm8333); return 0; - - free_irq: - free_irq(client->irq, lm8333); - free_mem: - input_free_device(input); - kfree(lm8333); - return err; -} - -static void lm8333_remove(struct i2c_client *client) -{ - struct lm8333 *lm8333 = i2c_get_clientdata(client); - - free_irq(client->irq, lm8333); - input_unregister_device(lm8333->input); - kfree(lm8333); } static const struct i2c_device_id lm8333_id[] = { @@ -219,7 +204,6 @@ static struct i2c_driver lm8333_driver = { .name = "lm8333", }, .probe = lm8333_probe, - .remove = lm8333_remove, .id_table = lm8333_id, }; module_i2c_driver(lm8333_driver); -- GitLab From caddca33a0177f452312f1644822bc98384ba58a Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Thu, 20 Jul 2023 15:38:03 -0700 Subject: [PATCH 0286/3445] Input: amikbd - convert to use devm_* api Use devm_* api to simplify code, this makes it unnecessary to explicitly release resources. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230714080611.81302-2-frank.li@vivo.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/amikbd.c | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c index a20a4e186639c..e305c44cd0aa9 100644 --- a/drivers/input/keyboard/amikbd.c +++ b/drivers/input/keyboard/amikbd.c @@ -196,7 +196,7 @@ static int __init amikbd_probe(struct platform_device *pdev) struct input_dev *dev; int i, err; - dev = input_allocate_device(); + dev = devm_input_allocate_device(&pdev->dev); if (!dev) { dev_err(&pdev->dev, "Not enough memory for input device\n"); return -ENOMEM; @@ -208,7 +208,6 @@ static int __init amikbd_probe(struct platform_device *pdev) dev->id.vendor = 0x0001; dev->id.product = 0x0001; dev->id.version = 0x0100; - dev->dev.parent = &pdev->dev; dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); @@ -218,35 +217,21 @@ static int __init amikbd_probe(struct platform_device *pdev) amikbd_init_console_keymaps(); ciaa.cra &= ~0x41; /* serial data in, turn off TA */ - err = request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd", - dev); + err = devm_request_irq(&pdev->dev, IRQ_AMIGA_CIAA_SP, amikbd_interrupt, + 0, "amikbd", dev); if (err) - goto fail2; + return err; err = input_register_device(dev); if (err) - goto fail3; + return err; platform_set_drvdata(pdev, dev); return 0; - - fail3: free_irq(IRQ_AMIGA_CIAA_SP, dev); - fail2: input_free_device(dev); - return err; -} - -static int __exit amikbd_remove(struct platform_device *pdev) -{ - struct input_dev *dev = platform_get_drvdata(pdev); - - free_irq(IRQ_AMIGA_CIAA_SP, dev); - input_unregister_device(dev); - return 0; } static struct platform_driver amikbd_driver = { - .remove = __exit_p(amikbd_remove), .driver = { .name = "amiga-keyboard", }, -- GitLab From e175eae16c1bf92062f1f431a95f476a61a77c48 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Thu, 20 Jul 2023 15:41:20 -0700 Subject: [PATCH 0287/3445] Input: mcs-touchkey - convert to use devm_* api Use devm_* api to simplify code, this makes it unnecessary to explicitly release resources. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230714080611.81302-3-frank.li@vivo.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/mcs_touchkey.c | 63 ++++++++++++--------------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c index de312d8eb974d..f25e2b20e2715 100644 --- a/drivers/input/keyboard/mcs_touchkey.c +++ b/drivers/input/keyboard/mcs_touchkey.c @@ -92,6 +92,13 @@ static irqreturn_t mcs_touchkey_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static void mcs_touchkey_poweroff(void *data) +{ + struct mcs_touchkey_data *touchkey = data; + + touchkey->poweron(false); +} + static int mcs_touchkey_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); @@ -109,13 +116,16 @@ static int mcs_touchkey_probe(struct i2c_client *client) return -EINVAL; } - data = kzalloc(struct_size(data, keycodes, pdata->key_maxval + 1), - GFP_KERNEL); - input_dev = input_allocate_device(); - if (!data || !input_dev) { - dev_err(&client->dev, "Failed to allocate memory\n"); - error = -ENOMEM; - goto err_free_mem; + data = devm_kzalloc(&client->dev, + struct_size(data, keycodes, pdata->key_maxval + 1), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + input_dev = devm_input_allocate_device(&client->dev); + if (!input_dev) { + dev_err(&client->dev, "Failed to allocate input device\n"); + return -ENOMEM; } data->client = client; @@ -136,15 +146,13 @@ static int mcs_touchkey_probe(struct i2c_client *client) fw_ver = i2c_smbus_read_byte_data(client, fw_reg); if (fw_ver < 0) { - error = fw_ver; dev_err(&client->dev, "i2c read error[%d]\n", error); - goto err_free_mem; + return fw_ver; } dev_info(&client->dev, "Firmware version: %d\n", fw_ver); input_dev->name = "MELFAS MCS Touchkey"; input_dev->id.bustype = BUS_I2C; - input_dev->dev.parent = &client->dev; input_dev->evbit[0] = BIT_MASK(EV_KEY); if (!pdata->no_autorepeat) input_dev->evbit[0] |= BIT_MASK(EV_REP); @@ -169,40 +177,28 @@ static int mcs_touchkey_probe(struct i2c_client *client) if (pdata->poweron) { data->poweron = pdata->poweron; data->poweron(true); + + error = devm_add_action_or_reset(&client->dev, + mcs_touchkey_poweroff, data); + if (error) + return error; } - error = request_threaded_irq(client->irq, NULL, mcs_touchkey_interrupt, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - client->dev.driver->name, data); + error = devm_request_threaded_irq(&client->dev, client->irq, + NULL, mcs_touchkey_interrupt, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + client->dev.driver->name, data); if (error) { dev_err(&client->dev, "Failed to register interrupt\n"); - goto err_free_mem; + return error; } error = input_register_device(input_dev); if (error) - goto err_free_irq; + return error; i2c_set_clientdata(client, data); return 0; - -err_free_irq: - free_irq(client->irq, data); -err_free_mem: - input_free_device(input_dev); - kfree(data); - return error; -} - -static void mcs_touchkey_remove(struct i2c_client *client) -{ - struct mcs_touchkey_data *data = i2c_get_clientdata(client); - - free_irq(client->irq, data); - if (data->poweron) - data->poweron(false); - input_unregister_device(data->input_dev); - kfree(data); } static void mcs_touchkey_shutdown(struct i2c_client *client) @@ -259,7 +255,6 @@ static struct i2c_driver mcs_touchkey_driver = { .pm = pm_sleep_ptr(&mcs_touchkey_pm_ops), }, .probe = mcs_touchkey_probe, - .remove = mcs_touchkey_remove, .shutdown = mcs_touchkey_shutdown, .id_table = mcs_touchkey_id, }; -- GitLab From 447c09544275663e1082f796b26c7959915c922a Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Thu, 20 Jul 2023 15:51:01 -0700 Subject: [PATCH 0288/3445] Input: qt1070 - convert to use devm_* api Use devm_* api to simplify code, this makes it unnecessary to explicitly release resources. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230714080611.81302-5-frank.li@vivo.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/qt1070.c | 46 ++++++++++----------------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c index 91aaa9fc43a4a..9b093b042bf19 100644 --- a/drivers/input/keyboard/qt1070.c +++ b/drivers/input/keyboard/qt1070.c @@ -149,20 +149,20 @@ static int qt1070_probe(struct i2c_client *client) if (!qt1070_identify(client)) return -ENODEV; - data = kzalloc(sizeof(struct qt1070_data), GFP_KERNEL); - input = input_allocate_device(); - if (!data || !input) { - dev_err(&client->dev, "insufficient memory\n"); - err = -ENOMEM; - goto err_free_mem; - } + data = devm_kzalloc(&client->dev, sizeof(struct qt1070_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + input = devm_input_allocate_device(&client->dev); + if (!input) + return -ENOMEM; data->client = client; data->input = input; data->irq = client->irq; input->name = "AT42QT1070 QTouch Sensor"; - input->dev.parent = &client->dev; input->id.bustype = BUS_I2C; /* Add the keycode */ @@ -185,19 +185,20 @@ static int qt1070_probe(struct i2c_client *client) qt1070_write(client, RESET, 1); msleep(QT1070_RESET_TIME); - err = request_threaded_irq(client->irq, NULL, qt1070_interrupt, - IRQF_TRIGGER_NONE | IRQF_ONESHOT, - client->dev.driver->name, data); + err = devm_request_threaded_irq(&client->dev, client->irq, + NULL, qt1070_interrupt, + IRQF_TRIGGER_NONE | IRQF_ONESHOT, + client->dev.driver->name, data); if (err) { dev_err(&client->dev, "fail to request irq\n"); - goto err_free_mem; + return err; } /* Register the input device */ err = input_register_device(data->input); if (err) { dev_err(&client->dev, "Failed to register input device\n"); - goto err_free_irq; + return err; } i2c_set_clientdata(client, data); @@ -206,24 +207,6 @@ static int qt1070_probe(struct i2c_client *client) qt1070_read(client, DET_STATUS); return 0; - -err_free_irq: - free_irq(client->irq, data); -err_free_mem: - input_free_device(input); - kfree(data); - return err; -} - -static void qt1070_remove(struct i2c_client *client) -{ - struct qt1070_data *data = i2c_get_clientdata(client); - - /* Release IRQ */ - free_irq(client->irq, data); - - input_unregister_device(data->input); - kfree(data); } static int qt1070_suspend(struct device *dev) @@ -272,7 +255,6 @@ static struct i2c_driver qt1070_driver = { }, .id_table = qt1070_id, .probe = qt1070_probe, - .remove = qt1070_remove, }; module_i2c_driver(qt1070_driver); -- GitLab From 714e08cc3ec564dc1717000f5a4c1f40ca8c8878 Mon Sep 17 00:00:00 2001 From: Haitao Huang Date: Fri, 21 Jul 2023 05:02:31 -0700 Subject: [PATCH 0289/3445] cgroup/misc: Store atomic64_t reads to u64 Change 'new_usage' type to u64 so it can be compared with unsigned 'max' and 'capacity' properly even if the value crosses the signed boundary. Signed-off-by: Haitao Huang Signed-off-by: Tejun Heo --- kernel/cgroup/misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/cgroup/misc.c b/kernel/cgroup/misc.c index abbe9aa5cdd17..79a3717a5803a 100644 --- a/kernel/cgroup/misc.c +++ b/kernel/cgroup/misc.c @@ -142,7 +142,7 @@ int misc_cg_try_charge(enum misc_res_type type, struct misc_cg *cg, u64 amount) struct misc_cg *i, *j; int ret; struct misc_res *res; - s64 new_usage; + u64 new_usage; if (!(valid_type(type) && cg && READ_ONCE(misc_res_capacity[type]))) return -EINVAL; -- GitLab From fe9ebb8cec7968e2e758670952bbe4f1a453ef08 Mon Sep 17 00:00:00 2001 From: Xiongwei Song Date: Fri, 21 Jul 2023 13:49:37 +0800 Subject: [PATCH 0290/3445] docs: cgroup-v1: correct the term of Page Cache organization in inode The radix-tree for Page Cache has been replaced with xarray, see commit eb797a8ee0ab ("page cache: Rearrange address_space"), so move "radix-tree" to "xarray". Signed-off-by: Xiongwei Song Signed-off-by: Tejun Heo --- Documentation/admin-guide/cgroup-v1/memory.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/admin-guide/cgroup-v1/memory.rst b/Documentation/admin-guide/cgroup-v1/memory.rst index fabaad3fd9c21..b49bae598a388 100644 --- a/Documentation/admin-guide/cgroup-v1/memory.rst +++ b/Documentation/admin-guide/cgroup-v1/memory.rst @@ -197,11 +197,11 @@ are not accounted. We just account pages under usual VM management. RSS pages are accounted at page_fault unless they've already been accounted for earlier. A file page will be accounted for as Page Cache when it's -inserted into inode (radix-tree). While it's mapped into the page tables of +inserted into inode (xarray). While it's mapped into the page tables of processes, duplicate accounting is carefully avoided. An RSS page is unaccounted when it's fully unmapped. A PageCache page is -unaccounted when it's removed from radix-tree. Even if RSS pages are fully +unaccounted when it's removed from xarray. Even if RSS pages are fully unmapped (by kswapd), they may exist as SwapCache in the system until they are really freed. Such SwapCaches are also accounted. A swapped-in page is accounted after adding into swapcache. -- GitLab From ab8aebdc9f7b9e2768c8a5776d028f4a10d05c4b Mon Sep 17 00:00:00 2001 From: Xiongwei Song Date: Fri, 21 Jul 2023 13:49:38 +0800 Subject: [PATCH 0291/3445] docs: cgroup-v1: fix typo "listers" -> "listeners" Signed-off-by: Xiongwei Song Signed-off-by: Tejun Heo --- Documentation/admin-guide/cgroup-v1/memory.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/admin-guide/cgroup-v1/memory.rst b/Documentation/admin-guide/cgroup-v1/memory.rst index b49bae598a388..304b8aae03c9b 100644 --- a/Documentation/admin-guide/cgroup-v1/memory.rst +++ b/Documentation/admin-guide/cgroup-v1/memory.rst @@ -909,7 +909,7 @@ experiences some pressure. In this situation, only group C will receive the notification, i.e. groups A and B will not receive it. This is done to avoid excessive "broadcasting" of messages, which disturbs the system and which is especially bad if we are low on memory or thrashing. Group B, will receive -notification only if there are no event listers for group C. +notification only if there are no event listeners for group C. There are three optional modes that specify different propagation behavior: -- GitLab From aecab554b6ffa9a94ba796031eb39ea20eb60fb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 14 Jul 2023 22:56:15 +0200 Subject: [PATCH 0292/3445] pwm: atmel-hlcdc: Use consistent variable naming MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In PWM drivers the variable name "chip" is usually only used for struct pwm_chip pointers. This driver however used "chip" for its driver data and pwm_chip pointers are named "chip", too, when there is no driver data around and "c" otherwise. Instead use "atmel" for driver data and always "chip" for pwm_chips. Signed-off-by: Uwe Kleine-König Reviewed-by: Claudiu Beznea [thierry.reding@gmail.com: replace ddata by atmel] Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel-hlcdc.c | 65 ++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c index 96a709a9d49a8..4d0b859d0ac13 100644 --- a/drivers/pwm/pwm-atmel-hlcdc.c +++ b/drivers/pwm/pwm-atmel-hlcdc.c @@ -38,11 +38,11 @@ static inline struct atmel_hlcdc_pwm *to_atmel_hlcdc_pwm(struct pwm_chip *chip) return container_of(chip, struct atmel_hlcdc_pwm, chip); } -static int atmel_hlcdc_pwm_apply(struct pwm_chip *c, struct pwm_device *pwm, +static int atmel_hlcdc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_state *state) { - struct atmel_hlcdc_pwm *chip = to_atmel_hlcdc_pwm(c); - struct atmel_hlcdc *hlcdc = chip->hlcdc; + struct atmel_hlcdc_pwm *atmel = to_atmel_hlcdc_pwm(chip); + struct atmel_hlcdc *hlcdc = atmel->hlcdc; unsigned int status; int ret; @@ -54,7 +54,7 @@ static int atmel_hlcdc_pwm_apply(struct pwm_chip *c, struct pwm_device *pwm, u32 pwmcfg; int pres; - if (!chip->errata || !chip->errata->slow_clk_erratum) { + if (!atmel->errata || !atmel->errata->slow_clk_erratum) { clk_freq = clk_get_rate(new_clk); if (!clk_freq) return -EINVAL; @@ -64,7 +64,7 @@ static int atmel_hlcdc_pwm_apply(struct pwm_chip *c, struct pwm_device *pwm, } /* Errata: cannot use slow clk on some IP revisions */ - if ((chip->errata && chip->errata->slow_clk_erratum) || + if ((atmel->errata && atmel->errata->slow_clk_erratum) || clk_period_ns > state->period) { new_clk = hlcdc->sys_clk; clk_freq = clk_get_rate(new_clk); @@ -77,8 +77,8 @@ static int atmel_hlcdc_pwm_apply(struct pwm_chip *c, struct pwm_device *pwm, for (pres = 0; pres <= ATMEL_HLCDC_PWMPS_MAX; pres++) { /* Errata: cannot divide by 1 on some IP revisions */ - if (!pres && chip->errata && - chip->errata->div1_clk_erratum) + if (!pres && atmel->errata && + atmel->errata->div1_clk_erratum) continue; if ((clk_period_ns << pres) >= state->period) @@ -90,7 +90,7 @@ static int atmel_hlcdc_pwm_apply(struct pwm_chip *c, struct pwm_device *pwm, pwmcfg = ATMEL_HLCDC_PWMPS(pres); - if (new_clk != chip->cur_clk) { + if (new_clk != atmel->cur_clk) { u32 gencfg = 0; int ret; @@ -98,8 +98,8 @@ static int atmel_hlcdc_pwm_apply(struct pwm_chip *c, struct pwm_device *pwm, if (ret) return ret; - clk_disable_unprepare(chip->cur_clk); - chip->cur_clk = new_clk; + clk_disable_unprepare(atmel->cur_clk); + atmel->cur_clk = new_clk; if (new_clk == hlcdc->sys_clk) gencfg = ATMEL_HLCDC_CLKPWMSEL; @@ -160,8 +160,8 @@ static int atmel_hlcdc_pwm_apply(struct pwm_chip *c, struct pwm_device *pwm, if (ret) return ret; - clk_disable_unprepare(chip->cur_clk); - chip->cur_clk = NULL; + clk_disable_unprepare(atmel->cur_clk); + atmel->cur_clk = NULL; } return 0; @@ -183,31 +183,32 @@ static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_sama5d3_errata = { #ifdef CONFIG_PM_SLEEP static int atmel_hlcdc_pwm_suspend(struct device *dev) { - struct atmel_hlcdc_pwm *chip = dev_get_drvdata(dev); + struct atmel_hlcdc_pwm *atmel = dev_get_drvdata(dev); /* Keep the periph clock enabled if the PWM is still running. */ - if (pwm_is_enabled(&chip->chip.pwms[0])) - clk_disable_unprepare(chip->hlcdc->periph_clk); + if (pwm_is_enabled(&atmel->chip.pwms[0])) + clk_disable_unprepare(atmel->hlcdc->periph_clk); return 0; } static int atmel_hlcdc_pwm_resume(struct device *dev) { - struct atmel_hlcdc_pwm *chip = dev_get_drvdata(dev); + struct atmel_hlcdc_pwm *atmel = dev_get_drvdata(dev); struct pwm_state state; int ret; - pwm_get_state(&chip->chip.pwms[0], &state); + pwm_get_state(&atmel->chip.pwms[0], &state); /* Re-enable the periph clock it was stopped during suspend. */ if (!state.enabled) { - ret = clk_prepare_enable(chip->hlcdc->periph_clk); + ret = clk_prepare_enable(atmel->hlcdc->periph_clk); if (ret) return ret; } - return atmel_hlcdc_pwm_apply(&chip->chip, &chip->chip.pwms[0], &state); + return atmel_hlcdc_pwm_apply(&atmel->chip, &atmel->chip.pwms[0], + &state); } #endif @@ -244,14 +245,14 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev) { const struct of_device_id *match; struct device *dev = &pdev->dev; - struct atmel_hlcdc_pwm *chip; + struct atmel_hlcdc_pwm *atmel; struct atmel_hlcdc *hlcdc; int ret; hlcdc = dev_get_drvdata(dev->parent); - chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); - if (!chip) + atmel = devm_kzalloc(dev, sizeof(*atmel), GFP_KERNEL); + if (!atmel) return -ENOMEM; ret = clk_prepare_enable(hlcdc->periph_clk); @@ -260,31 +261,31 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev) match = of_match_node(atmel_hlcdc_dt_ids, dev->parent->of_node); if (match) - chip->errata = match->data; + atmel->errata = match->data; - chip->hlcdc = hlcdc; - chip->chip.ops = &atmel_hlcdc_pwm_ops; - chip->chip.dev = dev; - chip->chip.npwm = 1; + atmel->hlcdc = hlcdc; + atmel->chip.ops = &atmel_hlcdc_pwm_ops; + atmel->chip.dev = dev; + atmel->chip.npwm = 1; - ret = pwmchip_add(&chip->chip); + ret = pwmchip_add(&atmel->chip); if (ret) { clk_disable_unprepare(hlcdc->periph_clk); return ret; } - platform_set_drvdata(pdev, chip); + platform_set_drvdata(pdev, atmel); return 0; } static void atmel_hlcdc_pwm_remove(struct platform_device *pdev) { - struct atmel_hlcdc_pwm *chip = platform_get_drvdata(pdev); + struct atmel_hlcdc_pwm *atmel = platform_get_drvdata(pdev); - pwmchip_remove(&chip->chip); + pwmchip_remove(&atmel->chip); - clk_disable_unprepare(chip->hlcdc->periph_clk); + clk_disable_unprepare(atmel->hlcdc->periph_clk); } static const struct of_device_id atmel_hlcdc_pwm_dt_ids[] = { -- GitLab From 51352c09eafdc53a8d5022ff00a69d1bf262a097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 14 Jul 2023 22:56:16 +0200 Subject: [PATCH 0293/3445] pwm: bcm-kona: Consistently name pwm_chip variables "chip" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most variables holding a pointer to a pwm_chip are called "chip" which is also the usual name in most other PWM drivers. Rename the single variable that have a different name to be called "chip", too, for consistency. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-bcm-kona.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c index 4fa6e249e4cf3..e5b00cc9f7a76 100644 --- a/drivers/pwm/pwm-bcm-kona.c +++ b/drivers/pwm/pwm-bcm-kona.c @@ -61,9 +61,9 @@ struct kona_pwmc { struct clk *clk; }; -static inline struct kona_pwmc *to_kona_pwmc(struct pwm_chip *_chip) +static inline struct kona_pwmc *to_kona_pwmc(struct pwm_chip *chip) { - return container_of(_chip, struct kona_pwmc, chip); + return container_of(chip, struct kona_pwmc, chip); } /* -- GitLab From 92f2de28288bacc1455e64c957b16d7e2f721d3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 14 Jul 2023 22:56:17 +0200 Subject: [PATCH 0294/3445] pwm: crc: Consistently name pwm_chip variables "chip" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most variables holding a pointer to a pwm_chip are called "chip" which is also the usual name in most other PWM drivers. Rename the single variable that have a different name to be called "chip", too, for consistency. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-crc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c index 4703b4a0b6e4a..b9f063dc6b5fd 100644 --- a/drivers/pwm/pwm-crc.c +++ b/drivers/pwm/pwm-crc.c @@ -34,9 +34,9 @@ struct crystalcove_pwm { struct regmap *regmap; }; -static inline struct crystalcove_pwm *to_crc_pwm(struct pwm_chip *pc) +static inline struct crystalcove_pwm *to_crc_pwm(struct pwm_chip *chip) { - return container_of(pc, struct crystalcove_pwm, chip); + return container_of(chip, struct crystalcove_pwm, chip); } static int crc_pwm_calc_clk_div(int period_ns) -- GitLab From 5996cdf132dad91db596d0bdacf137cbde68dc3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 14 Jul 2023 22:56:18 +0200 Subject: [PATCH 0295/3445] pwm: cros-ec: Consistently name pwm_chip variables "chip" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most variables holding a pointer to a pwm_chip are called "chip" which is also the usual name in most other PWM drivers. Rename the two variables that have a different name to be called "chip", too, for consistency. Signed-off-by: Uwe Kleine-König Reviewed-by: Tzung-Bi Shih Signed-off-by: Thierry Reding --- drivers/pwm/pwm-cros-ec.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c index 74e863aa1d8d4..154ca0f90847b 100644 --- a/drivers/pwm/pwm-cros-ec.c +++ b/drivers/pwm/pwm-cros-ec.c @@ -37,9 +37,9 @@ struct cros_ec_pwm { u16 duty_cycle; }; -static inline struct cros_ec_pwm_device *pwm_to_cros_ec_pwm(struct pwm_chip *c) +static inline struct cros_ec_pwm_device *pwm_to_cros_ec_pwm(struct pwm_chip *chip) { - return container_of(c, struct cros_ec_pwm_device, chip); + return container_of(chip, struct cros_ec_pwm_device, chip); } static int cros_ec_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) @@ -218,14 +218,14 @@ static int cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, } static struct pwm_device * -cros_ec_pwm_xlate(struct pwm_chip *pc, const struct of_phandle_args *args) +cros_ec_pwm_xlate(struct pwm_chip *chip, const struct of_phandle_args *args) { struct pwm_device *pwm; - if (args->args[0] >= pc->npwm) + if (args->args[0] >= chip->npwm) return ERR_PTR(-EINVAL); - pwm = pwm_request_from_chip(pc, args->args[0], NULL); + pwm = pwm_request_from_chip(chip, args->args[0], NULL); if (IS_ERR(pwm)) return pwm; -- GitLab From 1425c40189ebbcfbf59df7fcbe0e6f4716bc1dcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 14 Jul 2023 22:56:19 +0200 Subject: [PATCH 0296/3445] pwm: lp3943: Consistently name pwm_chip variables "chip" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most variables holding a pointer to a pwm_chip are called "chip" which is also the usual name in most other PWM drivers. Rename the single variable that have a different name to be called "chip", too, for consistency. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-lp3943.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm-lp3943.c b/drivers/pwm/pwm-lp3943.c index 35675e4058c6b..a39411b87e19b 100644 --- a/drivers/pwm/pwm-lp3943.c +++ b/drivers/pwm/pwm-lp3943.c @@ -24,9 +24,9 @@ struct lp3943_pwm { struct lp3943_platform_data *pdata; }; -static inline struct lp3943_pwm *to_lp3943_pwm(struct pwm_chip *_chip) +static inline struct lp3943_pwm *to_lp3943_pwm(struct pwm_chip *chip) { - return container_of(_chip, struct lp3943_pwm, chip); + return container_of(chip, struct lp3943_pwm, chip); } static struct lp3943_pwm_map * -- GitLab From 454a8f5967df2f41046011bbb1912d2febc66d12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 14 Jul 2023 22:56:20 +0200 Subject: [PATCH 0297/3445] pwm: rockchip: Consistently name pwm_chip variables "chip" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most variables holding a pointer to a pwm_chip are called "chip" which is also the usual name in most other PWM drivers. Rename the single variable that have a different name to be called "chip", too, for consistency. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-rockchip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c index c1a1f2d864b5e..03ee18fb82d5b 100644 --- a/drivers/pwm/pwm-rockchip.c +++ b/drivers/pwm/pwm-rockchip.c @@ -52,9 +52,9 @@ struct rockchip_pwm_data { u32 enable_conf; }; -static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c) +static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *chip) { - return container_of(c, struct rockchip_pwm_chip, chip); + return container_of(chip, struct rockchip_pwm_chip, chip); } static int rockchip_pwm_get_state(struct pwm_chip *chip, -- GitLab From daf3facb9373fe4d6a06f65e834becb16d40de7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 14 Jul 2023 22:56:21 +0200 Subject: [PATCH 0298/3445] pwm: sifive: Consistently name pwm_chip variables "chip" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most variables holding a pointer to a pwm_chip are called "chip" which is also the usual name in most other PWM drivers. Rename the single variable that have a different name to be called "chip", too, for consistency. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-sifive.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c index ae49d67ab2b1a..25b9b7d9476aa 100644 --- a/drivers/pwm/pwm-sifive.c +++ b/drivers/pwm/pwm-sifive.c @@ -51,9 +51,9 @@ struct pwm_sifive_ddata { }; static inline -struct pwm_sifive_ddata *pwm_sifive_chip_to_ddata(struct pwm_chip *c) +struct pwm_sifive_ddata *pwm_sifive_chip_to_ddata(struct pwm_chip *chip) { - return container_of(c, struct pwm_sifive_ddata, chip); + return container_of(chip, struct pwm_sifive_ddata, chip); } static int pwm_sifive_request(struct pwm_chip *chip, struct pwm_device *pwm) -- GitLab From bc83fe5cecf55f299e1c44061bfcabd1fc2a337b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 14 Jul 2023 22:56:22 +0200 Subject: [PATCH 0299/3445] pwm: sl28cpld: Consistently name pwm_chip variables "chip" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nearly all PWM drivers use the name "chip" for the member in the driver struct pointing to the pwm_chip. Also all local variables and function parameters with this type use this name. Rename the struct pwm_chip member accordingly for consistency. Also rename the parameter of the macro sl28cpld_pwm_from_chip to "chip". Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-sl28cpld.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/pwm/pwm-sl28cpld.c b/drivers/pwm/pwm-sl28cpld.c index e64900ad4ba1e..c789e934671ef 100644 --- a/drivers/pwm/pwm-sl28cpld.c +++ b/drivers/pwm/pwm-sl28cpld.c @@ -80,12 +80,15 @@ regmap_write((priv)->regmap, (priv)->offset + (reg), (val)) struct sl28cpld_pwm { - struct pwm_chip pwm_chip; + struct pwm_chip chip; struct regmap *regmap; u32 offset; }; -#define sl28cpld_pwm_from_chip(_chip) \ - container_of(_chip, struct sl28cpld_pwm, pwm_chip) + +static inline struct sl28cpld_pwm *sl28cpld_pwm_from_chip(struct pwm_chip *chip) +{ + return container_of(chip, struct sl28cpld_pwm, chip); +} static int sl28cpld_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, @@ -228,12 +231,12 @@ static int sl28cpld_pwm_probe(struct platform_device *pdev) } /* Initialize the pwm_chip structure */ - chip = &priv->pwm_chip; + chip = &priv->chip; chip->dev = &pdev->dev; chip->ops = &sl28cpld_pwm_ops; chip->npwm = 1; - ret = devm_pwmchip_add(&pdev->dev, &priv->pwm_chip); + ret = devm_pwmchip_add(&pdev->dev, chip); if (ret) { dev_err(&pdev->dev, "failed to add PWM chip (%pe)", ERR_PTR(ret)); -- GitLab From 16636297f5440117e8aa16cdd1f54b5874f6a3a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 14 Jul 2023 22:56:23 +0200 Subject: [PATCH 0300/3445] staging: greybus: pwm: Consistently name pwm_chip variables "chip" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All function parameters of type pointer to struct pwm_chip in this driver are called chip which is also the usual name of function parameters and local variables in most other PWM drivers. For consistency use the same name for the local variable of that type. Signed-off-by: Uwe Kleine-König Reviewed-by: Alex Elder Signed-off-by: Thierry Reding --- drivers/staging/greybus/pwm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/staging/greybus/pwm.c b/drivers/staging/greybus/pwm.c index 88da1d796f132..c483e1f0738e6 100644 --- a/drivers/staging/greybus/pwm.c +++ b/drivers/staging/greybus/pwm.c @@ -267,7 +267,7 @@ static int gb_pwm_probe(struct gbphy_device *gbphy_dev, { struct gb_connection *connection; struct gb_pwm_chip *pwmc; - struct pwm_chip *pwm; + struct pwm_chip *chip; int ret; pwmc = kzalloc(sizeof(*pwmc), GFP_KERNEL); @@ -295,13 +295,13 @@ static int gb_pwm_probe(struct gbphy_device *gbphy_dev, if (ret) goto exit_connection_disable; - pwm = &pwmc->chip; + chip = &pwmc->chip; - pwm->dev = &gbphy_dev->dev; - pwm->ops = &gb_pwm_ops; - pwm->npwm = pwmc->pwm_max + 1; + chip->dev = &gbphy_dev->dev; + chip->ops = &gb_pwm_ops; + chip->npwm = pwmc->pwm_max + 1; - ret = pwmchip_add(pwm); + ret = pwmchip_add(chip); if (ret) { dev_err(&gbphy_dev->dev, "failed to register PWM: %d\n", ret); -- GitLab From c619af83277872465cb74e7a351556fba97d85e8 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 27 Jun 2023 16:43:20 +0200 Subject: [PATCH 0301/3445] RDMA/erdma: use vmalloc_array and vcalloc Use vmalloc_array and vcalloc to protect against multiplication overflows. The changes were done using the following Coccinelle semantic patch: // @initialize:ocaml@ @@ let rename alloc = match alloc with "vmalloc" -> "vmalloc_array" | "vzalloc" -> "vcalloc" | _ -> failwith "unknown" @@ size_t e1,e2; constant C1, C2; expression E1, E2, COUNT, x1, x2, x3; typedef u8; typedef __u8; type t = {u8,__u8,char,unsigned char}; identifier alloc = {vmalloc,vzalloc}; fresh identifier realloc = script:ocaml(alloc) { rename alloc }; @@ ( alloc(x1*x2*x3) | alloc(C1 * C2) | alloc((sizeof(t)) * (COUNT), ...) | - alloc((e1) * (e2)) + realloc(e1, e2) | - alloc((e1) * (COUNT)) + realloc(COUNT, e1) | - alloc((E1) * (E2)) + realloc(E1, E2) ) // Link: https://lore.kernel.org/r/20230627144339.144478-6-Julia.Lawall@inria.fr Signed-off-by: Julia Lawall Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/erdma/erdma_verbs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/erdma/erdma_verbs.c b/drivers/infiniband/hw/erdma/erdma_verbs.c index 517676fbb8b11..fe0521f1536e0 100644 --- a/drivers/infiniband/hw/erdma/erdma_verbs.c +++ b/drivers/infiniband/hw/erdma/erdma_verbs.c @@ -481,8 +481,8 @@ static int init_kernel_qp(struct erdma_dev *dev, struct erdma_qp *qp, dev->func_bar + (ERDMA_SDB_SHARED_PAGE_INDEX << PAGE_SHIFT); kqp->hw_rq_db = dev->func_bar + ERDMA_BAR_RQDB_SPACE_OFFSET; - kqp->swr_tbl = vmalloc(qp->attrs.sq_size * sizeof(u64)); - kqp->rwr_tbl = vmalloc(qp->attrs.rq_size * sizeof(u64)); + kqp->swr_tbl = vmalloc_array(qp->attrs.sq_size, sizeof(u64)); + kqp->rwr_tbl = vmalloc_array(qp->attrs.rq_size, sizeof(u64)); if (!kqp->swr_tbl || !kqp->rwr_tbl) goto err_out; -- GitLab From 9191df0029266cd32ed8f47def22081e18f2d9b8 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 27 Jun 2023 16:43:29 +0200 Subject: [PATCH 0302/3445] RDMA/siw: use vmalloc_array and vcalloc Use vmalloc_array and vcalloc to protect against multiplication overflows. The changes were done using the following Coccinelle semantic patch: // @initialize:ocaml@ @@ let rename alloc = match alloc with "vmalloc" -> "vmalloc_array" | "vzalloc" -> "vcalloc" | _ -> failwith "unknown" @@ size_t e1,e2; constant C1, C2; expression E1, E2, COUNT, x1, x2, x3; typedef u8; typedef __u8; type t = {u8,__u8,char,unsigned char}; identifier alloc = {vmalloc,vzalloc}; fresh identifier realloc = script:ocaml(alloc) { rename alloc }; @@ ( alloc(x1*x2*x3) | alloc(C1 * C2) | alloc((sizeof(t)) * (COUNT), ...) | - alloc((e1) * (e2)) + realloc(e1, e2) | - alloc((e1) * (COUNT)) + realloc(COUNT, e1) | - alloc((E1) * (E2)) + realloc(E1, E2) ) // Link: https://lore.kernel.org/r/20230627144339.144478-15-Julia.Lawall@inria.fr Signed-off-by: Julia Lawall Signed-off-by: Jason Gunthorpe --- drivers/infiniband/sw/siw/siw_qp.c | 4 ++-- drivers/infiniband/sw/siw/siw_verbs.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw_qp.c b/drivers/infiniband/sw/siw/siw_qp.c index 81e9bbd9ebdac..47d0197db9a10 100644 --- a/drivers/infiniband/sw/siw/siw_qp.c +++ b/drivers/infiniband/sw/siw/siw_qp.c @@ -204,7 +204,7 @@ static int siw_qp_readq_init(struct siw_qp *qp, int irq_size, int orq_size) { if (irq_size) { irq_size = roundup_pow_of_two(irq_size); - qp->irq = vzalloc(irq_size * sizeof(struct siw_sqe)); + qp->irq = vcalloc(irq_size, sizeof(struct siw_sqe)); if (!qp->irq) { qp->attrs.irq_size = 0; return -ENOMEM; @@ -212,7 +212,7 @@ static int siw_qp_readq_init(struct siw_qp *qp, int irq_size, int orq_size) } if (orq_size) { orq_size = roundup_pow_of_two(orq_size); - qp->orq = vzalloc(orq_size * sizeof(struct siw_sqe)); + qp->orq = vcalloc(orq_size, sizeof(struct siw_sqe)); if (!qp->orq) { qp->attrs.orq_size = 0; qp->attrs.irq_size = 0; diff --git a/drivers/infiniband/sw/siw/siw_verbs.c b/drivers/infiniband/sw/siw/siw_verbs.c index 398ec13db6248..296d839ee876b 100644 --- a/drivers/infiniband/sw/siw/siw_verbs.c +++ b/drivers/infiniband/sw/siw/siw_verbs.c @@ -381,7 +381,7 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs, if (udata) qp->sendq = vmalloc_user(num_sqe * sizeof(struct siw_sqe)); else - qp->sendq = vzalloc(num_sqe * sizeof(struct siw_sqe)); + qp->sendq = vcalloc(num_sqe, sizeof(struct siw_sqe)); if (qp->sendq == NULL) { rv = -ENOMEM; @@ -414,7 +414,7 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs, qp->recvq = vmalloc_user(num_rqe * sizeof(struct siw_rqe)); else - qp->recvq = vzalloc(num_rqe * sizeof(struct siw_rqe)); + qp->recvq = vcalloc(num_rqe, sizeof(struct siw_rqe)); if (qp->recvq == NULL) { rv = -ENOMEM; @@ -1624,7 +1624,7 @@ int siw_create_srq(struct ib_srq *base_srq, srq->recvq = vmalloc_user(srq->num_rqe * sizeof(struct siw_rqe)); else - srq->recvq = vzalloc(srq->num_rqe * sizeof(struct siw_rqe)); + srq->recvq = vcalloc(srq->num_rqe, sizeof(struct siw_rqe)); if (srq->recvq == NULL) { rv = -ENOMEM; -- GitLab From 666f526b6dd1851184abc12f7901c813a097fa93 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 27 Jun 2023 16:43:34 +0200 Subject: [PATCH 0303/3445] RDMA/bnxt_re: use vmalloc_array and vcalloc Use vmalloc_array and vcalloc to protect against multiplication overflows. The changes were done using the following Coccinelle semantic patch: // @initialize:ocaml@ @@ let rename alloc = match alloc with "vmalloc" -> "vmalloc_array" | "vzalloc" -> "vcalloc" | _ -> failwith "unknown" @@ size_t e1,e2; constant C1, C2; expression E1, E2, COUNT, x1, x2, x3; typedef u8; typedef __u8; type t = {u8,__u8,char,unsigned char}; identifier alloc = {vmalloc,vzalloc}; fresh identifier realloc = script:ocaml(alloc) { rename alloc }; @@ ( alloc(x1*x2*x3) | alloc(C1 * C2) | alloc((sizeof(t)) * (COUNT), ...) | - alloc((e1) * (e2)) + realloc(e1, e2) | - alloc((e1) * (COUNT)) + realloc(COUNT, e1) | - alloc((E1) * (E2)) + realloc(E1, E2) ) // Link: https://lore.kernel.org/r/20230627144339.144478-20-Julia.Lawall@inria.fr Signed-off-by: Julia Lawall Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/qplib_res.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.c b/drivers/infiniband/hw/bnxt_re/qplib_res.c index 5fd8f7c90bb06..d47764c384611 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c @@ -118,11 +118,11 @@ static int __alloc_pbl(struct bnxt_qplib_res *res, else pages = sginfo->npages; /* page ptr arrays */ - pbl->pg_arr = vmalloc(pages * sizeof(void *)); + pbl->pg_arr = vmalloc_array(pages, sizeof(void *)); if (!pbl->pg_arr) return -ENOMEM; - pbl->pg_map_arr = vmalloc(pages * sizeof(dma_addr_t)); + pbl->pg_map_arr = vmalloc_array(pages, sizeof(dma_addr_t)); if (!pbl->pg_map_arr) { vfree(pbl->pg_arr); pbl->pg_arr = NULL; -- GitLab From bad5b6e34ffbaacc77ad28a0f482e33b3929e635 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 17 Jul 2023 11:12:12 -0400 Subject: [PATCH 0304/3445] RDMA/siw: Fabricate a GID on tun and loopback devices LOOPBACK and NONE (tunnel) devices have all-zero MAC addresses. Currently, siw_device_create() falls back to copying the IB device's name in those cases, because an all-zero MAC address breaks the RDMA core address resolution mechanism. However, at the point when siw_device_create() constructs a GID, the ib_device::name field is uninitialized, leaving the MAC address to remain in an all-zero state. Fabricate a random artificial GID for such devices, and ensure this artificial GID is returned for all device query operations. Link: https://lore.kernel.org/r/168960673260.3007.12378736853793339110.stgit@manet.1015granger.net Reported-by: Tom Talpey Fixes: a2d36b02c15d ("RDMA/siw: Enable siw on tunnel devices") Reviewed-by: Bernard Metzler Reviewed-by: Tom Talpey Signed-off-by: Chuck Lever Signed-off-by: Jason Gunthorpe --- drivers/infiniband/sw/siw/siw.h | 1 + drivers/infiniband/sw/siw/siw_main.c | 22 ++++++++-------------- drivers/infiniband/sw/siw/siw_verbs.c | 4 ++-- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw.h b/drivers/infiniband/sw/siw/siw.h index 2f3a9cda3850f..8b4a710b82bc1 100644 --- a/drivers/infiniband/sw/siw/siw.h +++ b/drivers/infiniband/sw/siw/siw.h @@ -74,6 +74,7 @@ struct siw_device { u32 vendor_part_id; int numa_node; + char raw_gid[ETH_ALEN]; /* physical port state (only one port per device) */ enum ib_port_state state; diff --git a/drivers/infiniband/sw/siw/siw_main.c b/drivers/infiniband/sw/siw/siw_main.c index 65b5cda5457ba..f45600d169ae7 100644 --- a/drivers/infiniband/sw/siw/siw_main.c +++ b/drivers/infiniband/sw/siw/siw_main.c @@ -75,8 +75,7 @@ static int siw_device_register(struct siw_device *sdev, const char *name) return rv; } - siw_dbg(base_dev, "HWaddr=%pM\n", sdev->netdev->dev_addr); - + siw_dbg(base_dev, "HWaddr=%pM\n", sdev->raw_gid); return 0; } @@ -313,24 +312,19 @@ static struct siw_device *siw_device_create(struct net_device *netdev) return NULL; base_dev = &sdev->base_dev; - sdev->netdev = netdev; - if (netdev->type != ARPHRD_LOOPBACK && netdev->type != ARPHRD_NONE) { - addrconf_addr_eui48((unsigned char *)&base_dev->node_guid, - netdev->dev_addr); + if (netdev->addr_len) { + memcpy(sdev->raw_gid, netdev->dev_addr, + min_t(unsigned int, netdev->addr_len, ETH_ALEN)); } else { /* - * This device does not have a HW address, - * but connection mangagement lib expects gid != 0 + * This device does not have a HW address, but + * connection mangagement requires a unique gid. */ - size_t len = min_t(size_t, strlen(base_dev->name), 6); - char addr[6] = { }; - - memcpy(addr, base_dev->name, len); - addrconf_addr_eui48((unsigned char *)&base_dev->node_guid, - addr); + eth_random_addr(sdev->raw_gid); } + addrconf_addr_eui48((u8 *)&base_dev->node_guid, sdev->raw_gid); base_dev->uverbs_cmd_mask |= BIT_ULL(IB_USER_VERBS_CMD_POST_SEND); diff --git a/drivers/infiniband/sw/siw/siw_verbs.c b/drivers/infiniband/sw/siw/siw_verbs.c index 296d839ee876b..fadfa70853f33 100644 --- a/drivers/infiniband/sw/siw/siw_verbs.c +++ b/drivers/infiniband/sw/siw/siw_verbs.c @@ -157,7 +157,7 @@ int siw_query_device(struct ib_device *base_dev, struct ib_device_attr *attr, attr->vendor_part_id = sdev->vendor_part_id; addrconf_addr_eui48((u8 *)&attr->sys_image_guid, - sdev->netdev->dev_addr); + sdev->raw_gid); return 0; } @@ -218,7 +218,7 @@ int siw_query_gid(struct ib_device *base_dev, u32 port, int idx, /* subnet_prefix == interface_id == 0; */ memset(gid, 0, sizeof(*gid)); - memcpy(&gid->raw[0], sdev->netdev->dev_addr, 6); + memcpy(gid->raw, sdev->raw_gid, ETH_ALEN); return 0; } -- GitLab From 448d15aab34293bf139f17c17910e854d9ad7d6c Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 17 Jul 2023 11:12:19 -0400 Subject: [PATCH 0305/3445] RDMA/core: Set gid_attr.ndev for iWARP devices Have the iwarp side properly set the ndev in the device's sgid_attrs so that address resolution can treat it more like a RoCE device. Link: https://lore.kernel.org/r/168960673933.3007.8043081822081877578.stgit@manet.1015granger.net Suggested-by: Jason Gunthorpe Reviewed-by: Tom Talpey Signed-off-by: Chuck Lever Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/cache.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index 2e91d88793265..33f9d02f9b600 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -1457,6 +1457,17 @@ static int config_non_roce_gid_cache(struct ib_device *device, i); goto err; } + + if (rdma_protocol_iwarp(device, port)) { + struct net_device *ndev; + + ndev = ib_device_get_netdev(device, port); + if (!ndev) + continue; + RCU_INIT_POINTER(gid_attr.ndev, ndev); + dev_put(ndev); + } + gid_attr.index = i; tprops->subnet_prefix = be64_to_cpu(gid_attr.gid.global.subnet_prefix); -- GitLab From 700c96497ba9acf1a3554a3cd3ba6c79db3cbcf7 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 17 Jul 2023 11:12:25 -0400 Subject: [PATCH 0306/3445] RDMA/cma: Deduplicate error flow in cma_validate_port() Clean up to prepare for the addition of new logic. Link: https://lore.kernel.org/r/168960674597.3007.6128252077812202526.stgit@manet.1015granger.net Signed-off-by: Chuck Lever Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/cma.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 1ee87c3aaeabc..da54167723d6e 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -686,30 +686,31 @@ cma_validate_port(struct ib_device *device, u32 port, struct rdma_id_private *id_priv) { struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; + const struct ib_gid_attr *sgid_attr = ERR_PTR(-ENODEV); int bound_if_index = dev_addr->bound_dev_if; - const struct ib_gid_attr *sgid_attr; int dev_type = dev_addr->dev_type; struct net_device *ndev = NULL; if (!rdma_dev_access_netns(device, id_priv->id.route.addr.dev_addr.net)) - return ERR_PTR(-ENODEV); + goto out; if ((dev_type == ARPHRD_INFINIBAND) && !rdma_protocol_ib(device, port)) - return ERR_PTR(-ENODEV); + goto out; if ((dev_type != ARPHRD_INFINIBAND) && rdma_protocol_ib(device, port)) - return ERR_PTR(-ENODEV); + goto out; if (dev_type == ARPHRD_ETHER && rdma_protocol_roce(device, port)) { ndev = dev_get_by_index(dev_addr->net, bound_if_index); if (!ndev) - return ERR_PTR(-ENODEV); + goto out; } else { gid_type = IB_GID_TYPE_IB; } sgid_attr = rdma_find_gid_by_port(device, gid, gid_type, port, ndev); dev_put(ndev); +out: return sgid_attr; } -- GitLab From f8ef1be816bf9a0c406c696368c2264a9597a994 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 17 Jul 2023 11:12:32 -0400 Subject: [PATCH 0307/3445] RDMA/cma: Avoid GID lookups on iWARP devices We would like to enable the use of siw on top of a VPN that is constructed and managed via a tun device. That hasn't worked up until now because ARPHRD_NONE devices (such as tun devices) have no GID for the RDMA/core to look up. But it turns out that the egress device has already been picked for us -- no GID is necessary. addr_handler() just has to do the right thing with it. Link: https://lore.kernel.org/r/168960675257.3007.4737911174148394395.stgit@manet.1015granger.net Suggested-by: Jason Gunthorpe Signed-off-by: Chuck Lever Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/cma.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index da54167723d6e..8bd6cb867381c 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -700,6 +700,27 @@ cma_validate_port(struct ib_device *device, u32 port, if ((dev_type != ARPHRD_INFINIBAND) && rdma_protocol_ib(device, port)) goto out; + /* + * For drivers that do not associate more than one net device with + * their gid tables, such as iWARP drivers, it is sufficient to + * return the first table entry. + * + * Other driver classes might be included in the future. + */ + if (rdma_protocol_iwarp(device, port)) { + sgid_attr = rdma_get_gid_attr(device, port, 0); + if (IS_ERR(sgid_attr)) + goto out; + + rcu_read_lock(); + ndev = rcu_dereference(sgid_attr->ndev); + if (!net_eq(dev_net(ndev), dev_addr->net) || + ndev->ifindex != bound_if_index) + sgid_attr = ERR_PTR(-ENODEV); + rcu_read_unlock(); + goto out; + } + if (dev_type == ARPHRD_ETHER && rdma_protocol_roce(device, port)) { ndev = dev_get_by_index(dev_addr->net, bound_if_index); if (!ndev) -- GitLab From cf1694f09894e760f4e2cf068ee6519d11cd0ede Mon Sep 17 00:00:00 2001 From: Chandramohan Akula Date: Tue, 18 Jul 2023 22:02:51 -0700 Subject: [PATCH 0308/3445] bnxt_en: Update HW interface headers Updating the HW structures for the doorbell pacing related information. Newly added interface structures will be used in the followup patches. Link: https://lore.kernel.org/r/1689742977-9128-2-git-send-email-selvin.xavier@broadcom.com CC: Michael Chan Signed-off-by: Chandramohan Akula Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h index b31de4cf6534b..a2d3a80236c4f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h @@ -3721,6 +3721,60 @@ struct hwrm_func_backing_store_qcaps_v2_output { u8 valid; }; +/* hwrm_func_dbr_pacing_qcfg_input (size:128b/16B) */ +struct hwrm_func_dbr_pacing_qcfg_input { + __le16 req_type; + __le16 cmpl_ring; + __le16 seq_id; + __le16 target_id; + __le64 resp_addr; +}; + +/* hwrm_func_dbr_pacing_qcfg_output (size:512b/64B) */ +struct hwrm_func_dbr_pacing_qcfg_output { + __le16 error_code; + __le16 req_type; + __le16 seq_id; + __le16 resp_len; + u8 flags; +#define FUNC_DBR_PACING_QCFG_RESP_FLAGS_DBR_NQ_EVENT_ENABLED 0x1UL + u8 unused_0[7]; + __le32 dbr_stat_db_fifo_reg; +#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_MASK 0x3UL +#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_SFT 0 +#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_PCIE_CFG 0x0UL +#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_GRC 0x1UL +#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_BAR0 0x2UL +#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_BAR1 0x3UL +#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_LAST \ + FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_BAR1 +#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_MASK 0xfffffffcUL +#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SFT 2 + __le32 dbr_stat_db_fifo_reg_watermark_mask; + u8 dbr_stat_db_fifo_reg_watermark_shift; + u8 unused_1[3]; + __le32 dbr_stat_db_fifo_reg_fifo_room_mask; + u8 dbr_stat_db_fifo_reg_fifo_room_shift; + u8 unused_2[3]; + __le32 dbr_throttling_aeq_arm_reg; +#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_MASK 0x3UL +#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_SFT 0 +#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_PCIE_CFG 0x0UL +#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_GRC 0x1UL +#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_BAR0 0x2UL +#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_BAR1 0x3UL +#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_LAST \ + FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_BAR1 +#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_MASK 0xfffffffcUL +#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SFT 2 + u8 dbr_throttling_aeq_arm_reg_val; + u8 unused_3[7]; + __le32 primary_nq_id; + __le32 pacing_threshold; + u8 unused_4[7]; + u8 valid; +}; + /* hwrm_func_drv_if_change_input (size:192b/24B) */ struct hwrm_func_drv_if_change_input { __le16 req_type; -- GitLab From 61220e098e858951f1926d66c1490a96351e1c85 Mon Sep 17 00:00:00 2001 From: Chandramohan Akula Date: Tue, 18 Jul 2023 22:02:52 -0700 Subject: [PATCH 0309/3445] bnxt_en: Share the bar0 address with the RoCE driver Add a parameter in the bnxt_en_dev structure to share the bar0 address with RoCE driver. Link: https://lore.kernel.org/r/1689742977-9128-3-git-send-email-selvin.xavier@broadcom.com CC: Michael Chan Signed-off-by: Chandramohan Akula Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c | 2 +- drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c index 852eb449ccae2..6ba2b93986333 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c @@ -345,7 +345,7 @@ static void bnxt_set_edev_info(struct bnxt_en_dev *edev, struct bnxt *bp) edev->hw_ring_stats_size = bp->hw_ring_stats_size; edev->pf_port_id = bp->pf.port_id; edev->en_state = bp->state; - + edev->bar0 = bp->bar0; edev->ulp_tbl->msix_requested = bnxt_get_ulp_msix_num(bp); } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h index 80cbc4b6130aa..6ff77f082e6c7 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h @@ -81,6 +81,7 @@ struct bnxt_en_dev { * mode only. Will be * updated in resume. */ + void __iomem *bar0; }; static inline bool bnxt_ulp_registered(struct bnxt_en_dev *edev) -- GitLab From 586e613d37ec35572a332839973b9c3bccd0c545 Mon Sep 17 00:00:00 2001 From: Chandramohan Akula Date: Tue, 18 Jul 2023 22:02:53 -0700 Subject: [PATCH 0310/3445] RDMA/bnxt_re: Initialize Doorbell pacing feature Checks for pacing feature capability and get the doorbell pacing configuration using FW commands. Allocate a page and initialize the pacing parameters for the applications. Cleanup the page and de-initialize the pacing during device removal. Link: https://lore.kernel.org/r/1689742977-9128-4-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Chandramohan Akula Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/bnxt_re.h | 22 ++++++ drivers/infiniband/hw/bnxt_re/main.c | 96 +++++++++++++++++++++++ drivers/infiniband/hw/bnxt_re/qplib_res.h | 19 +++++ 3 files changed, 137 insertions(+) diff --git a/drivers/infiniband/hw/bnxt_re/bnxt_re.h b/drivers/infiniband/hw/bnxt_re/bnxt_re.h index ea81b2497511a..1543f80a1b5c4 100644 --- a/drivers/infiniband/hw/bnxt_re/bnxt_re.h +++ b/drivers/infiniband/hw/bnxt_re/bnxt_re.h @@ -112,6 +112,27 @@ struct bnxt_re_gsi_context { #define BNXT_RE_NQ_IDX 1 #define BNXT_RE_GEN_P5_MAX_VF 64 +struct bnxt_re_pacing { + u64 dbr_db_fifo_reg_off; + void *dbr_page; + u64 dbr_bar_addr; + u32 pacing_algo_th; + u32 do_pacing_save; + u32 dbq_pacing_time; /* ms */ + u32 dbr_def_do_pacing; + bool dbr_pacing; +}; + +#define BNXT_RE_DBR_PACING_TIME 5 /* ms */ +#define BNXT_RE_PACING_ALGO_THRESHOLD 250 /* Entries in DB FIFO */ +#define BNXT_RE_PACING_ALARM_TH_MULTIPLE 2 /* Multiple of pacing algo threshold */ +/* Default do_pacing value when there is no congestion */ +#define BNXT_RE_DBR_DO_PACING_NO_CONGESTION 0x7F /* 1 in 512 probability */ +#define BNXT_RE_DB_FIFO_ROOM_MASK 0x1FFF8000 +#define BNXT_RE_MAX_FIFO_DEPTH 0x2c00 +#define BNXT_RE_DB_FIFO_ROOM_SHIFT 15 +#define BNXT_RE_GRC_FIFO_REG_BASE 0x2000 + struct bnxt_re_dev { struct ib_device ibdev; struct list_head list; @@ -171,6 +192,7 @@ struct bnxt_re_dev { atomic_t nq_alloc_cnt; u32 is_virtfn; u32 num_vfs; + struct bnxt_re_pacing pacing; }; #define to_bnxt_re_dev(ptr, member) \ diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index b42166fe74540..13cd84d68e1fd 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -432,9 +432,92 @@ int bnxt_re_hwrm_qcaps(struct bnxt_re_dev *rdev) return rc; cctx->modes.db_push = le32_to_cpu(resp.flags) & FUNC_QCAPS_RESP_FLAGS_WCB_PUSH_MODE; + cctx->modes.dbr_pacing = + le32_to_cpu(resp.flags_ext2) & FUNC_QCAPS_RESP_FLAGS_EXT2_DBR_PACING_EXT_SUPPORTED ? + true : false; return 0; } +static int bnxt_re_hwrm_dbr_pacing_qcfg(struct bnxt_re_dev *rdev) +{ + struct hwrm_func_dbr_pacing_qcfg_output resp = {}; + struct hwrm_func_dbr_pacing_qcfg_input req = {}; + struct bnxt_en_dev *en_dev = rdev->en_dev; + struct bnxt_qplib_chip_ctx *cctx; + struct bnxt_fw_msg fw_msg = {}; + int rc; + + cctx = rdev->chip_ctx; + bnxt_re_init_hwrm_hdr((void *)&req, HWRM_FUNC_DBR_PACING_QCFG); + bnxt_re_fill_fw_msg(&fw_msg, (void *)&req, sizeof(req), (void *)&resp, + sizeof(resp), DFLT_HWRM_CMD_TIMEOUT); + rc = bnxt_send_msg(en_dev, &fw_msg); + if (rc) + return rc; + + if ((le32_to_cpu(resp.dbr_stat_db_fifo_reg) & + FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_MASK) == + FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_GRC) + cctx->dbr_stat_db_fifo = + le32_to_cpu(resp.dbr_stat_db_fifo_reg) & + ~FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_MASK; + return 0; +} + +/* Update the pacing tunable parameters to the default values */ +static void bnxt_re_set_default_pacing_data(struct bnxt_re_dev *rdev) +{ + struct bnxt_qplib_db_pacing_data *pacing_data = rdev->qplib_res.pacing_data; + + pacing_data->do_pacing = rdev->pacing.dbr_def_do_pacing; + pacing_data->pacing_th = rdev->pacing.pacing_algo_th; + pacing_data->alarm_th = + pacing_data->pacing_th * BNXT_RE_PACING_ALARM_TH_MULTIPLE; +} + +static int bnxt_re_initialize_dbr_pacing(struct bnxt_re_dev *rdev) +{ + if (bnxt_re_hwrm_dbr_pacing_qcfg(rdev)) + return -EIO; + + /* Allocate a page for app use */ + rdev->pacing.dbr_page = (void *)__get_free_page(GFP_KERNEL); + if (!rdev->pacing.dbr_page) + return -ENOMEM; + + memset((u8 *)rdev->pacing.dbr_page, 0, PAGE_SIZE); + rdev->qplib_res.pacing_data = (struct bnxt_qplib_db_pacing_data *)rdev->pacing.dbr_page; + + /* MAP HW window 2 for reading db fifo depth */ + writel(rdev->chip_ctx->dbr_stat_db_fifo & BNXT_GRC_BASE_MASK, + rdev->en_dev->bar0 + BNXT_GRCPF_REG_WINDOW_BASE_OUT + 4); + rdev->pacing.dbr_db_fifo_reg_off = + (rdev->chip_ctx->dbr_stat_db_fifo & BNXT_GRC_OFFSET_MASK) + + BNXT_RE_GRC_FIFO_REG_BASE; + rdev->pacing.dbr_bar_addr = + pci_resource_start(rdev->qplib_res.pdev, 0) + rdev->pacing.dbr_db_fifo_reg_off; + + rdev->pacing.pacing_algo_th = BNXT_RE_PACING_ALGO_THRESHOLD; + rdev->pacing.dbq_pacing_time = BNXT_RE_DBR_PACING_TIME; + rdev->pacing.dbr_def_do_pacing = BNXT_RE_DBR_DO_PACING_NO_CONGESTION; + rdev->pacing.do_pacing_save = rdev->pacing.dbr_def_do_pacing; + rdev->qplib_res.pacing_data->fifo_max_depth = BNXT_RE_MAX_FIFO_DEPTH; + rdev->qplib_res.pacing_data->fifo_room_mask = BNXT_RE_DB_FIFO_ROOM_MASK; + rdev->qplib_res.pacing_data->fifo_room_shift = BNXT_RE_DB_FIFO_ROOM_SHIFT; + rdev->qplib_res.pacing_data->grc_reg_offset = rdev->pacing.dbr_db_fifo_reg_off; + bnxt_re_set_default_pacing_data(rdev); + return 0; +} + +static void bnxt_re_deinitialize_dbr_pacing(struct bnxt_re_dev *rdev) +{ + if (rdev->pacing.dbr_page) + free_page((u64)rdev->pacing.dbr_page); + + rdev->pacing.dbr_page = NULL; + rdev->pacing.dbr_pacing = false; +} + static int bnxt_re_net_ring_free(struct bnxt_re_dev *rdev, u16 fw_ring_id, int type) { @@ -1217,6 +1300,9 @@ static void bnxt_re_dev_uninit(struct bnxt_re_dev *rdev) if (test_and_clear_bit(BNXT_RE_FLAG_GOT_MSIX, &rdev->flags)) rdev->num_msix = 0; + if (rdev->pacing.dbr_pacing) + bnxt_re_deinitialize_dbr_pacing(rdev); + bnxt_re_destroy_chip_ctx(rdev); if (test_and_clear_bit(BNXT_RE_FLAG_NETDEV_REGISTERED, &rdev->flags)) bnxt_unregister_dev(rdev->en_dev); @@ -1309,6 +1395,16 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 wqe_mode) goto free_ring; } + if (bnxt_qplib_dbr_pacing_en(rdev->chip_ctx)) { + rc = bnxt_re_initialize_dbr_pacing(rdev); + if (!rc) { + rdev->pacing.dbr_pacing = true; + } else { + ibdev_err(&rdev->ibdev, + "DBR pacing disabled with error : %d\n", rc); + rdev->pacing.dbr_pacing = false; + } + } rc = bnxt_qplib_get_dev_attr(&rdev->rcfw, &rdev->dev_attr, rdev->is_virtfn); if (rc) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.h b/drivers/infiniband/hw/bnxt_re/qplib_res.h index d850a553821e3..57161d303c257 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.h @@ -48,6 +48,7 @@ extern const struct bnxt_qplib_gid bnxt_qplib_gid_zero; struct bnxt_qplib_drv_modes { u8 wqe_mode; bool db_push; + bool dbr_pacing; }; struct bnxt_qplib_chip_ctx { @@ -58,6 +59,17 @@ struct bnxt_qplib_chip_ctx { u16 hwrm_cmd_max_timeout; struct bnxt_qplib_drv_modes modes; u64 hwrm_intf_ver; + u32 dbr_stat_db_fifo; +}; + +struct bnxt_qplib_db_pacing_data { + u32 do_pacing; + u32 pacing_th; + u32 alarm_th; + u32 fifo_max_depth; + u32 fifo_room_mask; + u32 fifo_room_shift; + u32 grc_reg_offset; }; #define BNXT_QPLIB_DBR_PF_DB_OFFSET 0x10000 @@ -271,6 +283,7 @@ struct bnxt_qplib_res { struct mutex dpi_tbl_lock; bool prio; bool is_vf; + struct bnxt_qplib_db_pacing_data *pacing_data; }; static inline bool bnxt_qplib_is_chip_gen_p5(struct bnxt_qplib_chip_ctx *cctx) @@ -467,4 +480,10 @@ static inline bool _is_ext_stats_supported(u16 dev_cap_flags) return dev_cap_flags & CREQ_QUERY_FUNC_RESP_SB_EXT_STATS; } + +static inline u8 bnxt_qplib_dbr_pacing_en(struct bnxt_qplib_chip_ctx *cctx) +{ + return cctx->modes.dbr_pacing; +} + #endif /* __BNXT_QPLIB_RES_H__ */ -- GitLab From fa8fad92ddddfc0cfb6fd9e9f645cf53a5ee78a6 Mon Sep 17 00:00:00 2001 From: Chandramohan Akula Date: Tue, 18 Jul 2023 22:02:54 -0700 Subject: [PATCH 0311/3445] RDMA/bnxt_re: Enable pacing support for the user apps Report the pacing capability to the user applications. Link: https://lore.kernel.org/r/1689742977-9128-5-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Chandramohan Akula Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 2 ++ include/uapi/rdma/bnxt_re-abi.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index abef0b8baa7c3..86b71c77b6061 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -4075,6 +4075,8 @@ int bnxt_re_alloc_ucontext(struct ib_ucontext *ctx, struct ib_udata *udata) goto cfail; } uctx->shpage_mmap = &entry->rdma_entry; + if (rdev->pacing.dbr_pacing) + resp.comp_mask |= BNXT_RE_UCNTX_CMASK_DBR_PACING_ENABLED; rc = ib_copy_to_udata(udata, &resp, min(udata->outlen, sizeof(resp))); if (rc) { diff --git a/include/uapi/rdma/bnxt_re-abi.h b/include/uapi/rdma/bnxt_re-abi.h index 8a2a1d4f6b297..060bf1d1e3ee6 100644 --- a/include/uapi/rdma/bnxt_re-abi.h +++ b/include/uapi/rdma/bnxt_re-abi.h @@ -53,6 +53,7 @@ enum { BNXT_RE_UCNTX_CMASK_HAVE_CCTX = 0x1ULL, BNXT_RE_UCNTX_CMASK_HAVE_MODE = 0x02ULL, BNXT_RE_UCNTX_CMASK_WC_DPI_ENABLED = 0x04ULL, + BNXT_RE_UCNTX_CMASK_DBR_PACING_ENABLED = 0x08ULL, }; enum bnxt_re_wqe_mode { -- GitLab From ea222485788208cd79bad42d25aae9232b33a934 Mon Sep 17 00:00:00 2001 From: Chandramohan Akula Date: Tue, 18 Jul 2023 22:02:55 -0700 Subject: [PATCH 0312/3445] RDMA/bnxt_re: Update alloc_page uapi for pacing Update the alloc_page uapi functionality for handling the mapping of doorbell pacing shared page and bar address. Link: https://lore.kernel.org/r/1689742977-9128-6-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Chandramohan Akula Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 35 ++++++++++++++++++++++-- drivers/infiniband/hw/bnxt_re/ib_verbs.h | 2 ++ include/uapi/rdma/bnxt_re-abi.h | 2 ++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index 86b71c77b6061..0703163b397fe 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -565,6 +565,8 @@ bnxt_re_mmap_entry_insert(struct bnxt_re_ucontext *uctx, u64 mem_offset, break; case BNXT_RE_MMAP_UC_DB: case BNXT_RE_MMAP_WC_DB: + case BNXT_RE_MMAP_DBR_BAR: + case BNXT_RE_MMAP_DBR_PAGE: ret = rdma_user_mmap_entry_insert(&uctx->ib_uctx, &entry->rdma_entry, PAGE_SIZE); break; @@ -4149,6 +4151,19 @@ int bnxt_re_mmap(struct ib_ucontext *ib_uctx, struct vm_area_struct *vma) case BNXT_RE_MMAP_SH_PAGE: ret = vm_insert_page(vma, vma->vm_start, virt_to_page(uctx->shpg)); break; + case BNXT_RE_MMAP_DBR_BAR: + pfn = bnxt_entry->mem_offset >> PAGE_SHIFT; + ret = rdma_user_mmap_io(ib_uctx, vma, pfn, PAGE_SIZE, + pgprot_noncached(vma->vm_page_prot), + rdma_entry); + break; + case BNXT_RE_MMAP_DBR_PAGE: + /* Driver doesn't expect write access for user space */ + if (vma->vm_flags & VM_WRITE) + return -EFAULT; + ret = vm_insert_page(vma, vma->vm_start, + virt_to_page((void *)bnxt_entry->mem_offset)); + break; default: ret = -EINVAL; break; @@ -4180,7 +4195,7 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_ALLOC_PAGE)(struct uverbs_attr_bundle * u64 mmap_offset; u32 length; u32 dpi; - u64 dbr; + u64 addr; int err; uctx = container_of(ib_uverbs_get_ucontext(attrs), struct bnxt_re_ucontext, ib_uctx); @@ -4202,19 +4217,30 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_ALLOC_PAGE)(struct uverbs_attr_bundle * return -ENOMEM; length = PAGE_SIZE; dpi = uctx->wcdpi.dpi; - dbr = (u64)uctx->wcdpi.umdbr; + addr = (u64)uctx->wcdpi.umdbr; mmap_flag = BNXT_RE_MMAP_WC_DB; } else { return -EINVAL; } break; + case BNXT_RE_ALLOC_DBR_BAR_PAGE: + length = PAGE_SIZE; + addr = (u64)rdev->pacing.dbr_bar_addr; + mmap_flag = BNXT_RE_MMAP_DBR_BAR; + break; + + case BNXT_RE_ALLOC_DBR_PAGE: + length = PAGE_SIZE; + addr = (u64)rdev->pacing.dbr_page; + mmap_flag = BNXT_RE_MMAP_DBR_PAGE; + break; default: return -EOPNOTSUPP; } - entry = bnxt_re_mmap_entry_insert(uctx, dbr, mmap_flag, &mmap_offset); + entry = bnxt_re_mmap_entry_insert(uctx, addr, mmap_flag, &mmap_offset); if (!entry) return -ENOMEM; @@ -4254,6 +4280,9 @@ static int alloc_page_obj_cleanup(struct ib_uobject *uobject, uctx->wcdpi.dbr = NULL; } break; + case BNXT_RE_MMAP_DBR_BAR: + case BNXT_RE_MMAP_DBR_PAGE: + break; default: goto exit; } diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.h b/drivers/infiniband/hw/bnxt_re/ib_verbs.h index 32d9e9d09791e..f392a09b9e2c1 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.h +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.h @@ -146,6 +146,8 @@ enum bnxt_re_mmap_flag { BNXT_RE_MMAP_SH_PAGE, BNXT_RE_MMAP_UC_DB, BNXT_RE_MMAP_WC_DB, + BNXT_RE_MMAP_DBR_PAGE, + BNXT_RE_MMAP_DBR_BAR, }; struct bnxt_re_user_mmap_entry { diff --git a/include/uapi/rdma/bnxt_re-abi.h b/include/uapi/rdma/bnxt_re-abi.h index 060bf1d1e3ee6..78a324ff100b7 100644 --- a/include/uapi/rdma/bnxt_re-abi.h +++ b/include/uapi/rdma/bnxt_re-abi.h @@ -136,6 +136,8 @@ enum bnxt_re_objects { enum bnxt_re_alloc_page_type { BNXT_RE_ALLOC_WC_PAGE = 0, + BNXT_RE_ALLOC_DBR_BAR_PAGE, + BNXT_RE_ALLOC_DBR_PAGE, }; enum bnxt_re_var_alloc_page_attrs { -- GitLab From 2ad4e6303a6d7518632739eaf67821a3553db1bd Mon Sep 17 00:00:00 2001 From: Chandramohan Akula Date: Tue, 18 Jul 2023 22:02:56 -0700 Subject: [PATCH 0313/3445] RDMA/bnxt_re: Implement doorbell pacing algorithm User applications alert the driver when the Doorbell FIFO reaches the alarm threshold. The driver updates the pacing parameters in the shared page to do the maximum pacing by the application till the DB FIFO congestion reduces to pacing threshold. Driver keeps checking the DB FIFO depth at the pacing interval and gradually adjusts the pacing level. Once the pacing level reaches default values (no congestion in the FIFO) pacing gets completed. Link: https://lore.kernel.org/r/1689742977-9128-7-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Chandramohan Akula Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/bnxt_re.h | 5 + drivers/infiniband/hw/bnxt_re/main.c | 124 ++++++++++++++++++++++++ 2 files changed, 129 insertions(+) diff --git a/drivers/infiniband/hw/bnxt_re/bnxt_re.h b/drivers/infiniband/hw/bnxt_re/bnxt_re.h index 1543f80a1b5c4..2175103d570f2 100644 --- a/drivers/infiniband/hw/bnxt_re/bnxt_re.h +++ b/drivers/infiniband/hw/bnxt_re/bnxt_re.h @@ -121,8 +121,10 @@ struct bnxt_re_pacing { u32 dbq_pacing_time; /* ms */ u32 dbr_def_do_pacing; bool dbr_pacing; + struct mutex dbq_lock; /* synchronize db pacing algo */ }; +#define BNXT_RE_MAX_DBR_DO_PACING 0xFFFF #define BNXT_RE_DBR_PACING_TIME 5 /* ms */ #define BNXT_RE_PACING_ALGO_THRESHOLD 250 /* Entries in DB FIFO */ #define BNXT_RE_PACING_ALARM_TH_MULTIPLE 2 /* Multiple of pacing algo threshold */ @@ -193,6 +195,8 @@ struct bnxt_re_dev { u32 is_virtfn; u32 num_vfs; struct bnxt_re_pacing pacing; + struct work_struct dbq_fifo_check_work; + struct delayed_work dbq_pacing_work; }; #define to_bnxt_re_dev(ptr, member) \ @@ -203,6 +207,7 @@ struct bnxt_re_dev { #define BNXT_RE_ROCEV2_IPV6_PACKET 3 #define BNXT_RE_CHECK_RC(x) ((x) && ((x) != -ETIMEDOUT)) +void bnxt_re_pacing_alert(struct bnxt_re_dev *rdev); static inline struct device *rdev_to_dev(struct bnxt_re_dev *rdev) { diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index 13cd84d68e1fd..6469811003f6d 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -475,6 +475,125 @@ static void bnxt_re_set_default_pacing_data(struct bnxt_re_dev *rdev) pacing_data->pacing_th * BNXT_RE_PACING_ALARM_TH_MULTIPLE; } +static void __wait_for_fifo_occupancy_below_th(struct bnxt_re_dev *rdev) +{ + u32 read_val, fifo_occup; + + /* loop shouldn't run infintely as the occupancy usually goes + * below pacing algo threshold as soon as pacing kicks in. + */ + while (1) { + read_val = readl(rdev->en_dev->bar0 + rdev->pacing.dbr_db_fifo_reg_off); + fifo_occup = BNXT_RE_MAX_FIFO_DEPTH - + ((read_val & BNXT_RE_DB_FIFO_ROOM_MASK) >> + BNXT_RE_DB_FIFO_ROOM_SHIFT); + /* Fifo occupancy cannot be greater the MAX FIFO depth */ + if (fifo_occup > BNXT_RE_MAX_FIFO_DEPTH) + break; + + if (fifo_occup < rdev->qplib_res.pacing_data->pacing_th) + break; + } +} + +static void bnxt_re_db_fifo_check(struct work_struct *work) +{ + struct bnxt_re_dev *rdev = container_of(work, struct bnxt_re_dev, + dbq_fifo_check_work); + struct bnxt_qplib_db_pacing_data *pacing_data; + u32 pacing_save; + + if (!mutex_trylock(&rdev->pacing.dbq_lock)) + return; + pacing_data = rdev->qplib_res.pacing_data; + pacing_save = rdev->pacing.do_pacing_save; + __wait_for_fifo_occupancy_below_th(rdev); + cancel_delayed_work_sync(&rdev->dbq_pacing_work); + if (pacing_save > rdev->pacing.dbr_def_do_pacing) { + /* Double the do_pacing value during the congestion */ + pacing_save = pacing_save << 1; + } else { + /* + * when a new congestion is detected increase the do_pacing + * by 8 times. And also increase the pacing_th by 4 times. The + * reason to increase pacing_th is to give more space for the + * queue to oscillate down without getting empty, but also more + * room for the queue to increase without causing another alarm. + */ + pacing_save = pacing_save << 3; + pacing_data->pacing_th = rdev->pacing.pacing_algo_th * 4; + } + + if (pacing_save > BNXT_RE_MAX_DBR_DO_PACING) + pacing_save = BNXT_RE_MAX_DBR_DO_PACING; + + pacing_data->do_pacing = pacing_save; + rdev->pacing.do_pacing_save = pacing_data->do_pacing; + pacing_data->alarm_th = + pacing_data->pacing_th * BNXT_RE_PACING_ALARM_TH_MULTIPLE; + schedule_delayed_work(&rdev->dbq_pacing_work, + msecs_to_jiffies(rdev->pacing.dbq_pacing_time)); + mutex_unlock(&rdev->pacing.dbq_lock); +} + +static void bnxt_re_pacing_timer_exp(struct work_struct *work) +{ + struct bnxt_re_dev *rdev = container_of(work, struct bnxt_re_dev, + dbq_pacing_work.work); + struct bnxt_qplib_db_pacing_data *pacing_data; + u32 read_val, fifo_occup; + + if (!mutex_trylock(&rdev->pacing.dbq_lock)) + return; + + pacing_data = rdev->qplib_res.pacing_data; + read_val = readl(rdev->en_dev->bar0 + rdev->pacing.dbr_db_fifo_reg_off); + fifo_occup = BNXT_RE_MAX_FIFO_DEPTH - + ((read_val & BNXT_RE_DB_FIFO_ROOM_MASK) >> + BNXT_RE_DB_FIFO_ROOM_SHIFT); + + if (fifo_occup > pacing_data->pacing_th) + goto restart_timer; + + /* + * Instead of immediately going back to the default do_pacing + * reduce it by 1/8 times and restart the timer. + */ + pacing_data->do_pacing = pacing_data->do_pacing - (pacing_data->do_pacing >> 3); + pacing_data->do_pacing = max_t(u32, rdev->pacing.dbr_def_do_pacing, pacing_data->do_pacing); + if (pacing_data->do_pacing <= rdev->pacing.dbr_def_do_pacing) { + bnxt_re_set_default_pacing_data(rdev); + goto dbq_unlock; + } + +restart_timer: + schedule_delayed_work(&rdev->dbq_pacing_work, + msecs_to_jiffies(rdev->pacing.dbq_pacing_time)); +dbq_unlock: + rdev->pacing.do_pacing_save = pacing_data->do_pacing; + mutex_unlock(&rdev->pacing.dbq_lock); +} + +void bnxt_re_pacing_alert(struct bnxt_re_dev *rdev) +{ + struct bnxt_qplib_db_pacing_data *pacing_data; + + if (!rdev->pacing.dbr_pacing) + return; + mutex_lock(&rdev->pacing.dbq_lock); + pacing_data = rdev->qplib_res.pacing_data; + + /* + * Increase the alarm_th to max so that other user lib instances do not + * keep alerting the driver. + */ + pacing_data->alarm_th = BNXT_RE_MAX_FIFO_DEPTH; + pacing_data->do_pacing = BNXT_RE_MAX_DBR_DO_PACING; + cancel_work_sync(&rdev->dbq_fifo_check_work); + schedule_work(&rdev->dbq_fifo_check_work); + mutex_unlock(&rdev->pacing.dbq_lock); +} + static int bnxt_re_initialize_dbr_pacing(struct bnxt_re_dev *rdev) { if (bnxt_re_hwrm_dbr_pacing_qcfg(rdev)) @@ -506,11 +625,16 @@ static int bnxt_re_initialize_dbr_pacing(struct bnxt_re_dev *rdev) rdev->qplib_res.pacing_data->fifo_room_shift = BNXT_RE_DB_FIFO_ROOM_SHIFT; rdev->qplib_res.pacing_data->grc_reg_offset = rdev->pacing.dbr_db_fifo_reg_off; bnxt_re_set_default_pacing_data(rdev); + /* Initialize worker for DBR Pacing */ + INIT_WORK(&rdev->dbq_fifo_check_work, bnxt_re_db_fifo_check); + INIT_DELAYED_WORK(&rdev->dbq_pacing_work, bnxt_re_pacing_timer_exp); return 0; } static void bnxt_re_deinitialize_dbr_pacing(struct bnxt_re_dev *rdev) { + cancel_work_sync(&rdev->dbq_fifo_check_work); + cancel_delayed_work_sync(&rdev->dbq_pacing_work); if (rdev->pacing.dbr_page) free_page((u64)rdev->pacing.dbr_page); -- GitLab From 61a8118f60e9dde64be4f3a6e07c15014a8bfbd2 Mon Sep 17 00:00:00 2001 From: Chandramohan Akula Date: Tue, 18 Jul 2023 22:02:57 -0700 Subject: [PATCH 0314/3445] RDMA/bnxt_re: Add a new uapi for driver notification Add driver notify uapi for application notifying the driver about the doorbell FIFO congestion. Link: https://lore.kernel.org/r/1689742977-9128-8-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Chandramohan Akula Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 15 +++++++++++++++ include/uapi/rdma/bnxt_re-abi.h | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index 0703163b397fe..ec4d163f3f525 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -4183,6 +4183,15 @@ void bnxt_re_mmap_free(struct rdma_user_mmap_entry *rdma_entry) kfree(bnxt_entry); } +static int UVERBS_HANDLER(BNXT_RE_METHOD_NOTIFY_DRV)(struct uverbs_attr_bundle *attrs) +{ + struct bnxt_re_ucontext *uctx; + + uctx = container_of(ib_uverbs_get_ucontext(attrs), struct bnxt_re_ucontext, ib_uctx); + bnxt_re_pacing_alert(uctx->rdev); + return 0; +} + static int UVERBS_HANDLER(BNXT_RE_METHOD_ALLOC_PAGE)(struct uverbs_attr_bundle *attrs) { struct ib_uobject *uobj = uverbs_attr_get_uobject(attrs, BNXT_RE_ALLOC_PAGE_HANDLE); @@ -4320,7 +4329,13 @@ DECLARE_UVERBS_NAMED_OBJECT(BNXT_RE_OBJECT_ALLOC_PAGE, &UVERBS_METHOD(BNXT_RE_METHOD_ALLOC_PAGE), &UVERBS_METHOD(BNXT_RE_METHOD_DESTROY_PAGE)); +DECLARE_UVERBS_NAMED_METHOD(BNXT_RE_METHOD_NOTIFY_DRV); + +DECLARE_UVERBS_GLOBAL_METHODS(BNXT_RE_OBJECT_NOTIFY_DRV, + &UVERBS_METHOD(BNXT_RE_METHOD_NOTIFY_DRV)); + const struct uapi_definition bnxt_re_uapi_defs[] = { UAPI_DEF_CHAIN_OBJ_TREE_NAMED(BNXT_RE_OBJECT_ALLOC_PAGE), + UAPI_DEF_CHAIN_OBJ_TREE_NAMED(BNXT_RE_OBJECT_NOTIFY_DRV), {} }; diff --git a/include/uapi/rdma/bnxt_re-abi.h b/include/uapi/rdma/bnxt_re-abi.h index 78a324ff100b7..6e7c67a0cca3a 100644 --- a/include/uapi/rdma/bnxt_re-abi.h +++ b/include/uapi/rdma/bnxt_re-abi.h @@ -132,6 +132,7 @@ enum bnxt_re_shpg_offt { enum bnxt_re_objects { BNXT_RE_OBJECT_ALLOC_PAGE = (1U << UVERBS_ID_NS_SHIFT), + BNXT_RE_OBJECT_NOTIFY_DRV, }; enum bnxt_re_alloc_page_type { @@ -157,4 +158,7 @@ enum bnxt_re_alloc_page_methods { BNXT_RE_METHOD_DESTROY_PAGE, }; +enum bnxt_re_notify_drv_methods { + BNXT_RE_METHOD_NOTIFY_DRV = (1U << UVERBS_ID_NS_SHIFT), +}; #endif /* __BNXT_RE_UVERBS_ABI_H__*/ -- GitLab From a3fdeeb3f1c1fad3b7b07aa96a7e422fde3c2c15 Mon Sep 17 00:00:00 2001 From: Miaohe Lin Date: Wed, 19 Jul 2023 17:06:40 +0800 Subject: [PATCH 0315/3445] cgroup: fix obsolete comment above cgroup_create() Since commit 743210386c03 ("cgroup: use cgrp->kn->id as the cgroup ID"), cgrp is associated with its kernfs_node. Update corresponding comment. Signed-off-by: Miaohe Lin Signed-off-by: Tejun Heo --- kernel/cgroup/cgroup.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 3c1bb9ecea105..c7aafb59ecf24 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -5545,8 +5545,7 @@ err_free_css: /* * The returned cgroup is fully initialized including its control mask, but - * it isn't associated with its kernfs_node and doesn't have the control - * mask applied. + * it doesn't have the control mask applied. */ static struct cgroup *cgroup_create(struct cgroup *parent, const char *name, umode_t mode) -- GitLab From abfac0f3a457dab837fc74e47f00d829976fb0a6 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 21 Jul 2023 20:09:11 +0300 Subject: [PATCH 0316/3445] mtd: spi-nor: spansion: return method directly Remove unnecessary handling of method's return code and return the method directly. Link: https://lore.kernel.org/r/20230721170911.13502-1-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 6d6466a3436e6..314667d4b8a89 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -656,13 +656,7 @@ static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, const struct sfdp_bfpt *bfpt) { - int ret; - - ret = cypress_nor_set_addr_mode_nbytes(nor); - if (ret) - return ret; - - return 0; + return cypress_nor_set_addr_mode_nbytes(nor); } static void s28hx_t_late_init(struct spi_nor *nor) -- GitLab From 2f5833ead7ea332889cfbdd4ac7b84279fdd3cef Mon Sep 17 00:00:00 2001 From: Minjie Du Date: Wed, 5 Jul 2023 18:39:50 +0800 Subject: [PATCH 0317/3445] RDMA/qedr: Remove a duplicate assignment in qedr_create_gsi_qp() Delete a duplicate statement from this function implementation. Signed-off-by: Minjie Du Link: https://lore.kernel.org/r/20230705103950.15225-1-duminjie@vivo.com Acked-by: Alok Prasad Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/qedr/qedr_roce_cm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/infiniband/hw/qedr/qedr_roce_cm.c b/drivers/infiniband/hw/qedr/qedr_roce_cm.c index 05307c1488b83..859f66a51bd25 100644 --- a/drivers/infiniband/hw/qedr/qedr_roce_cm.c +++ b/drivers/infiniband/hw/qedr/qedr_roce_cm.c @@ -354,7 +354,6 @@ int qedr_create_gsi_qp(struct qedr_dev *dev, struct ib_qp_init_attr *attrs, /* the GSI CQ is handled by the driver so remove it from the FW */ qedr_destroy_gsi_cq(dev, attrs); dev->gsi_rqcq->cq_type = QEDR_CQ_TYPE_GSI; - dev->gsi_rqcq->cq_type = QEDR_CQ_TYPE_GSI; DP_DEBUG(dev, QEDR_MSG_GSI, "created GSI QP %p\n", qp); -- GitLab From 44725a87381353075273618eeedc9127e99c378e Mon Sep 17 00:00:00 2001 From: Minjie Du Date: Wed, 5 Jul 2023 11:18:49 +0800 Subject: [PATCH 0318/3445] RDMA/qedr: Remove duplicate assignments of va Avoid double assignment of iwqp->ietf_mem.va. Signed-off-by: Minjie Du Link: https://lore.kernel.org/r/20230705031849.2443-1-duminjie@vivo.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/irdma/cm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/infiniband/hw/irdma/cm.c b/drivers/infiniband/hw/irdma/cm.c index 8ea55c6a3fba5..70017048d7d18 100644 --- a/drivers/infiniband/hw/irdma/cm.c +++ b/drivers/infiniband/hw/irdma/cm.c @@ -3627,7 +3627,6 @@ void irdma_free_lsmm_rsrc(struct irdma_qp *iwqp) iwqp->ietf_mem.size, iwqp->ietf_mem.va, iwqp->ietf_mem.pa); iwqp->ietf_mem.va = NULL; - iwqp->ietf_mem.va = NULL; } } -- GitLab From a959dbd98d1aeb51dec1cc7e5ada5d84ce16cbbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Wed, 19 Jul 2023 16:00:07 +0200 Subject: [PATCH 0319/3445] tomoyo: add format attributes to functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Format attributes on functions taking format string can help compilers detect argument type or count mismatches. Please the compiler when building with W=1: security/tomoyo/audit.c: In function ‘tomoyo_init_log’: security/tomoyo/audit.c:290:9: error: function ‘tomoyo_init_log’ might be a candidate for ‘gnu_printf’ format attribute [-Werror=suggest-attribute=format] 290 | vsnprintf(buf + pos, len - pos, fmt, args); | ^~~~~~~~~ security/tomoyo/audit.c: In function ‘tomoyo_write_log2’: security/tomoyo/audit.c:376:9: error: function ‘tomoyo_write_log2’ might be a candidate for ‘gnu_printf’ format attribute [-Werror=suggest-attribute=format] 376 | buf = tomoyo_init_log(r, len, fmt, args); | ^~~ security/tomoyo/common.c: In function ‘tomoyo_addprintf’: security/tomoyo/common.c:193:9: error: function ‘tomoyo_addprintf’ might be a candidate for ‘gnu_printf’ format attribute [-Werror=suggest-attribute=format] 193 | vsnprintf(buffer + pos, len - pos - 1, fmt, args); | ^~~~~~~~~ Signed-off-by: Christian Göttsche Signed-off-by: Tetsuo Handa --- security/tomoyo/common.c | 1 + security/tomoyo/common.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 969d4aa6fd556..57ee70ae50f24 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -184,6 +184,7 @@ static bool tomoyo_manage_by_non_root; * * Returns nothing. */ +__printf(3, 4) static void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...) { va_list args; diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index a539b2cbb5c45..e669837ed0e31 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -954,7 +954,7 @@ bool tomoyo_str_starts(char **src, const char *find); char *tomoyo_encode(const char *str); char *tomoyo_encode2(const char *str, int str_len); char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt, - va_list args); + va_list args) __printf(3, 0); char *tomoyo_read_token(struct tomoyo_acl_param *param); char *tomoyo_realpath_from_path(const struct path *path); char *tomoyo_realpath_nofollow(const char *pathname); @@ -1067,7 +1067,7 @@ void tomoyo_warn_oom(const char *function); void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...) __printf(2, 3); void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt, - va_list args); + va_list args) __printf(3, 0); /********** External variable definitions. **********/ -- GitLab From a9814b6c23e79ed58aeb432d7f1c556935aeaf8d Mon Sep 17 00:00:00 2001 From: Udit Kumar Date: Mon, 10 Jul 2023 15:18:01 +0530 Subject: [PATCH 0320/3445] scsi: ufs: ti-j721e: Expose device tree aliases When TI UFS host controller driver is built as kernel module it is not getting auto-loaded due to missing aliases in modules. Add device tree related aliases. Signed-off-by: Udit Kumar Link: https://lore.kernel.org/r/20230710094801.183149-1-u-kumar1@ti.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ti-j721e-ufs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ufs/host/ti-j721e-ufs.c b/drivers/ufs/host/ti-j721e-ufs.c index 122d650d08102..117eb7da92acd 100644 --- a/drivers/ufs/host/ti-j721e-ufs.c +++ b/drivers/ufs/host/ti-j721e-ufs.c @@ -81,6 +81,8 @@ static const struct of_device_id ti_j721e_ufs_of_match[] = { { }, }; +MODULE_DEVICE_TABLE(of, ti_j721e_ufs_of_match); + static struct platform_driver ti_j721e_ufs_driver = { .probe = ti_j721e_ufs_probe, .remove = ti_j721e_ufs_remove, -- GitLab From f5393a5602cacfda2014e0ff8220e5a7564e7cd1 Mon Sep 17 00:00:00 2001 From: Xingui Yang Date: Tue, 11 Jul 2023 11:14:58 +0800 Subject: [PATCH 0321/3445] scsi: hisi_sas: Fix normally completed I/O analysed as failed The PIO read command has no response frame and the struct iu[1024] won't be filled. I/Os which are normally completed will be treated as failed in sas_ata_task_done() when iu contains abnormal dirty data. Consequently ending_fis should not be filled by iu when the response frame hasn't been written to memory. Fixes: d380f55503ed ("scsi: hisi_sas: Don't bother clearing status buffer IU in task prep") Signed-off-by: Xingui Yang Signed-off-by: Xiang Chen Link: https://lore.kernel.org/r/1689045300-44318-2-git-send-email-chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 11 +++++++++-- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 6 ++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 87d8e408ccd1c..404aa7e179cba 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2026,6 +2026,11 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, u16 dma_tx_err_type = le16_to_cpu(err_record->dma_tx_err_type); u16 sipc_rx_err_type = le16_to_cpu(err_record->sipc_rx_err_type); u32 dma_rx_err_type = le32_to_cpu(err_record->dma_rx_err_type); + struct hisi_sas_complete_v2_hdr *complete_queue = + hisi_hba->complete_hdr[slot->cmplt_queue]; + struct hisi_sas_complete_v2_hdr *complete_hdr = + &complete_queue[slot->cmplt_queue_slot]; + u32 dw0 = le32_to_cpu(complete_hdr->dw0); int error = -1; if (err_phase == 1) { @@ -2310,7 +2315,8 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, break; } } - hisi_sas_sata_done(task, slot); + if (dw0 & CMPLT_HDR_RSPNS_XFRD_MSK) + hisi_sas_sata_done(task, slot); } break; default: @@ -2443,7 +2449,8 @@ static void slot_complete_v2_hw(struct hisi_hba *hisi_hba, case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: { ts->stat = SAS_SAM_STAT_GOOD; - hisi_sas_sata_done(task, slot); + if (dw0 & CMPLT_HDR_RSPNS_XFRD_MSK) + hisi_sas_sata_done(task, slot); break; } default: diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 20e1607c62828..2f33e6b4a92fb 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -2257,7 +2257,8 @@ slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task, ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; } - hisi_sas_sata_done(task, slot); + if (dw0 & CMPLT_HDR_RSPNS_XFRD_MSK) + hisi_sas_sata_done(task, slot); break; case SAS_PROTOCOL_SMP: ts->stat = SAS_SAM_STAT_CHECK_CONDITION; @@ -2384,7 +2385,8 @@ static void slot_complete_v3_hw(struct hisi_hba *hisi_hba, case SAS_PROTOCOL_STP: case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: ts->stat = SAS_SAM_STAT_GOOD; - hisi_sas_sata_done(task, slot); + if (dw0 & CMPLT_HDR_RSPNS_XFRD_MSK) + hisi_sas_sata_done(task, slot); break; default: ts->stat = SAS_SAM_STAT_CHECK_CONDITION; -- GitLab From 32be33747d5dd46dde869de390e434f3deb25d2e Mon Sep 17 00:00:00 2001 From: Yihang Li Date: Tue, 11 Jul 2023 11:14:59 +0800 Subject: [PATCH 0322/3445] scsi: hisi_sas: Block requests before a debugfs snapshot When FIO and debugfs snapshot occur concurrently, some SATA I/Os are failed to return to the upper layer due to the setting of HISI_SAS_REJECT_CMD_BIT. Then the SCSI layer invokes the error processing thread. However, sas_ata_hard_reset() in EH also fails to be reset due to the setting of HISI_SAS_REJECT_CMD_BIT. As a result, the device is disabled. Calling scsi_block_requests() in the front of a debugfs snapshot and wait command complete before setting HISI_SAS_REJECT_CMD_BIT to avoid SATA I/O failures. Signed-off-by: Yihang Li Signed-off-by: Xiang Chen Link: https://lore.kernel.org/r/1689045300-44318-3-git-send-email-chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 2f33e6b4a92fb..7aad495d78e58 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -3106,21 +3106,25 @@ static const struct hisi_sas_debugfs_reg debugfs_ras_reg = { static void debugfs_snapshot_prepare_v3_hw(struct hisi_hba *hisi_hba) { - set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); - - hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0); + struct Scsi_Host *shost = hisi_hba->shost; + scsi_block_requests(shost); wait_cmds_complete_timeout_v3_hw(hisi_hba, 100, 5000); + set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); hisi_sas_sync_cqs(hisi_hba); + hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0); } static void debugfs_snapshot_restore_v3_hw(struct hisi_hba *hisi_hba) { + struct Scsi_Host *shost = hisi_hba->shost; + hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, (u32)((1ULL << hisi_hba->queue_count) - 1)); clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); + scsi_unblock_requests(shost); } static void read_iost_itct_cache_v3_hw(struct hisi_hba *hisi_hba, -- GitLab From 29f45ed18aa9b75b99126ea675dd29757b621073 Mon Sep 17 00:00:00 2001 From: Yihang Li Date: Tue, 11 Jul 2023 11:15:00 +0800 Subject: [PATCH 0323/3445] scsi: hisi_sas: Delete unused lock in hisi_sas_port_notify_formed() Currently spinlock hisi_hba->lock is used by both interrupts and threads which requires the use of spin_lock_irqsave()/spin_unlock_irqrestore(). However, some places still use spin_lock()/spin_unlock(). Reviewing the code revealed that it is unnecessary to use hisi_hba->lock in the function hisi_sas_port_notify_formed() which is the only place that uses the spinlock in interrupt context. So delete unused lock in hisi_sas_port_notify_formed(). Signed-off-by: Yihang Li Signed-off-by: Xiang Chen Link: https://lore.kernel.org/r/1689045300-44318-4-git-send-email-chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 8f22ece957bd4..7a62590f8730b 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1065,23 +1065,18 @@ EXPORT_SYMBOL_GPL(hisi_sas_phy_enable); static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy) { - struct sas_ha_struct *sas_ha = sas_phy->ha; - struct hisi_hba *hisi_hba = sas_ha->lldd_ha; struct hisi_sas_phy *phy = sas_phy->lldd_phy; struct asd_sas_port *sas_port = sas_phy->port; struct hisi_sas_port *port; - unsigned long flags; if (!sas_port) return; port = to_hisi_sas_port(sas_port); - spin_lock_irqsave(&hisi_hba->lock, flags); port->port_attached = 1; port->id = phy->port_id; phy->port = port; sas_port->lldd_port = port; - spin_unlock_irqrestore(&hisi_hba->lock, flags); } static void hisi_sas_do_release_task(struct hisi_hba *hisi_hba, struct sas_task *task, -- GitLab From 8f2b78652d0552e157a0b9cd354f2e5c20ba98ca Mon Sep 17 00:00:00 2001 From: Ziqi Chen Date: Tue, 11 Jul 2023 15:59:08 +0800 Subject: [PATCH 0324/3445] scsi: ufs: qcom: Get queue ID from MSI index in ESI handler platform_msi_domain_alloc_irqs() does not always get consecutive IRQ numbers, hence queue IDs calculated out from IRQ numbers may be incorrect if we assume IRQ numbers are consecutive. Fix this by passing msi_desc to ESI handler to use msi_desc->msi_index as queue ID. Co-developed-by: Can Guo Signed-off-by: Can Guo Signed-off-by: Ziqi Chen Link: https://lore.kernel.org/r/1689062349-77385-1-git-send-email-quic_ziqichen@quicinc.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 25 ++++++++++--------------- drivers/ufs/host/ufs-qcom.h | 1 - 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 8d6fd4c3324f2..f36bcdbea938e 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1643,11 +1643,13 @@ static void ufs_qcom_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg) ufshcd_mcq_config_esi(hba, msg); } -static irqreturn_t ufs_qcom_mcq_esi_handler(int irq, void *__hba) +static irqreturn_t ufs_qcom_mcq_esi_handler(int irq, void *data) { - struct ufs_hba *hba = __hba; + struct msi_desc *desc = data; + struct device *dev = msi_desc_to_dev(desc); + struct ufs_hba *hba = dev_get_drvdata(dev); struct ufs_qcom_host *host = ufshcd_get_variant(hba); - u32 id = irq - host->esi_base; + u32 id = desc->msi_index; struct ufs_hw_queue *hwq = &hba->uhq[id]; ufshcd_mcq_write_cqis(hba, 0x1, id); @@ -1665,8 +1667,6 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba) if (host->esi_enabled) return 0; - else if (host->esi_base < 0) - return -EINVAL; /* * 1. We only handle CQs as of now. @@ -1675,16 +1675,15 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba) nr_irqs = hba->nr_hw_queues - hba->nr_queues[HCTX_TYPE_POLL]; ret = platform_msi_domain_alloc_irqs(hba->dev, nr_irqs, ufs_qcom_write_msi_msg); - if (ret) + if (ret) { + dev_err(hba->dev, "Failed to request Platform MSI %d\n", ret); goto out; + } msi_for_each_desc(desc, hba->dev, MSI_DESC_ALL) { - if (!desc->msi_index) - host->esi_base = desc->irq; - ret = devm_request_irq(hba->dev, desc->irq, ufs_qcom_mcq_esi_handler, - IRQF_SHARED, "qcom-mcq-esi", hba); + IRQF_SHARED, "qcom-mcq-esi", desc); if (ret) { dev_err(hba->dev, "%s: Fail to request IRQ for %d, err = %d\n", __func__, desc->irq, ret); @@ -1712,12 +1711,8 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba) } out: - if (ret) { - host->esi_base = -1; - dev_warn(hba->dev, "Failed to request Platform MSI %d\n", ret); - } else { + if (!ret) host->esi_enabled = true; - } return ret; } diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index 6289ad5a42d0b..729240367e702 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -226,7 +226,6 @@ struct ufs_qcom_host { u32 hs_gear; - int esi_base; bool esi_enabled; }; -- GitLab From f52a805e19b169989ec6c61254529b273a18116d Mon Sep 17 00:00:00 2001 From: Ziqi Chen Date: Tue, 11 Jul 2023 16:48:46 +0800 Subject: [PATCH 0325/3445] scsi: ufs: qcom: Hold the mutex lock when configuring ESI Lock the MSI descriptor storage of a device when configuring ESI. Otherwise we would see warnings during boot. Signed-off-by: Ziqi Chen Link: https://lore.kernel.org/r/1689065327-45039-1-git-send-email-quic_ziqichen@quicinc.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index f36bcdbea938e..d29e63e4a4f8f 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1680,6 +1680,7 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba) goto out; } + msi_lock_descs(hba->dev); msi_for_each_desc(desc, hba->dev, MSI_DESC_ALL) { ret = devm_request_irq(hba->dev, desc->irq, ufs_qcom_mcq_esi_handler, @@ -1691,14 +1692,17 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba) break; } } + msi_unlock_descs(hba->dev); if (ret) { /* Rewind */ + msi_lock_descs(hba->dev); msi_for_each_desc(desc, hba->dev, MSI_DESC_ALL) { if (desc == failed_desc) break; devm_free_irq(hba->dev, desc->irq, hba); } + msi_unlock_descs(hba->dev); platform_msi_domain_free_irqs(hba->dev); } else { if (host->hw_ver.major == 6 && host->hw_ver.minor == 0 && -- GitLab From 75aa298739fdff5dac98e5a6e8b9106c1297d6f0 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Wed, 12 Jul 2023 14:48:32 +0800 Subject: [PATCH 0326/3445] scsi: ufs: ufs-mediatek: Remove redundant dev_err() There is no need to call the dev_err() function directly to print a custom message when handling an error from either the platform_get_irq() or platform_get_irq_byname() functions as both are going to display an appropriate error message in case of a failure. ./drivers/ufs/host/ufs-mediatek.c:864:3-10: line 864 is redundant because platform_get_irq() already prints an error Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=5846 Signed-off-by: Yang Li Link: https://lore.kernel.org/r/20230712064832.44188-1-yang.lee@linux.alibaba.com Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index 786b1469eb52c..b499eade957ee 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -861,7 +861,6 @@ static void ufs_mtk_init_mcq_irq(struct ufs_hba *hba) irq = platform_get_irq(pdev, i + 1); if (irq < 0) { host->mcq_intr_info[i].irq = MTK_MCQ_INVALID_IRQ; - dev_err(hba->dev, "get platform mcq irq fail: %d\n", i); goto failed; } host->mcq_intr_info[i].hba = hba; -- GitLab From 317a38045ab763fb98570b67848ebc65c731b570 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Wed, 12 Jul 2023 15:58:36 +0800 Subject: [PATCH 0327/3445] scsi: ufs: core: Fix some kernel-doc comments Use colons to separate parameter names from their specific meanings to silence the following warnings: drivers/ufs/core/ufs-mcq.c:499: warning: Function parameter or member 'hba' not described in 'ufshcd_mcq_sq_cleanup' drivers/ufs/core/ufs-mcq.c:499: warning: Function parameter or member 'task_tag' not described in 'ufshcd_mcq_sq_cleanup' drivers/ufs/core/ufs-mcq.c:560: warning: Function parameter or member 'utrd' not described in 'ufshcd_mcq_nullify_sqe' drivers/ufs/core/ufs-mcq.c:583: warning: Function parameter or member 'hba' not described in 'ufshcd_mcq_sqe_search' drivers/ufs/core/ufs-mcq.c:583: warning: Function parameter or member 'hwq' not described in 'ufshcd_mcq_sqe_search' drivers/ufs/core/ufs-mcq.c:583: warning: Function parameter or member 'task_tag' not described in 'ufshcd_mcq_sqe_search' drivers/ufs/core/ufs-mcq.c:630: warning: Function parameter or member 'cmd' not described in 'ufshcd_mcq_abort' Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=5850 Signed-off-by: Yang Li Link: https://lore.kernel.org/r/20230712075836.15375-1-yang.lee@linux.alibaba.com Reviewed-by: Randy Dunlap Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-mcq.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index e8bad5e9518e3..1e23ba3e2bdf0 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -490,8 +490,8 @@ static int ufshcd_mcq_sq_start(struct ufs_hba *hba, struct ufs_hw_queue *hwq) /** * ufshcd_mcq_sq_cleanup - Clean up submission queue resources * associated with the pending command. - * @hba - per adapter instance. - * @task_tag - The command's task tag. + * @hba: per adapter instance. + * @task_tag: The command's task tag. * * Returns 0 for success; error code otherwise. */ @@ -554,7 +554,7 @@ unlock: * Write the sqe's Command Type to 0xF. The host controller will not * fetch any sqe with Command Type = 0xF. * - * @utrd - UTP Transfer Request Descriptor to be nullified. + * @utrd: UTP Transfer Request Descriptor to be nullified. */ static void ufshcd_mcq_nullify_sqe(struct utp_transfer_req_desc *utrd) { @@ -571,9 +571,9 @@ static void ufshcd_mcq_nullify_sqe(struct utp_transfer_req_desc *utrd) * If the command is in the submission queue and not issued to the device yet, * nullify the sqe so the host controller will skip fetching the sqe. * - * @hba - per adapter instance. - * @hwq - Hardware Queue to be searched. - * @task_tag - The command's task tag. + * @hba: per adapter instance. + * @hwq: Hardware Queue to be searched. + * @task_tag: The command's task tag. * * Returns true if the SQE containing the command is present in the SQ * (not fetched by the controller); returns false if the SQE is not in the SQ. @@ -622,7 +622,7 @@ out: /** * ufshcd_mcq_abort - Abort the command in MCQ. - * @cmd - The command to be aborted. + * @cmd: The command to be aborted. * * Returns SUCCESS or FAILED error codes */ -- GitLab From c2ab666072bcf5bf181b84f591e83713e772fa60 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Jul 2023 11:50:18 -0600 Subject: [PATCH 0328/3445] scsi: ufs: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230714175018.4064957-1-robh@kernel.org Acked-by: Yoshihiro Shimoda Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 1 + drivers/ufs/host/ufs-renesas.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index b499eade957ee..10a28079c8bb0 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/ufs/host/ufs-renesas.c b/drivers/ufs/host/ufs-renesas.c index f8a5e79ed3b4e..49f7bafc7d558 100644 --- a/drivers/ufs/host/ufs-renesas.c +++ b/drivers/ufs/host/ufs-renesas.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include -- GitLab From c4ca20f0f1286039f9bc09310e1853dd4ff6c22e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Jul 2023 11:50:52 -0600 Subject: [PATCH 0329/3445] scsi: qlogicpti: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230714175052.4066150-1-robh@kernel.org Signed-off-by: Martin K. Petersen --- drivers/scsi/qlogicpti.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index 1e8fbd4572485..f88a5421c483f 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include -- GitLab From 109a2a48fc3d4b59f69b5be6ea05544ac8b4dded Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Jul 2023 11:50:52 -0600 Subject: [PATCH 0330/3445] scsi: sun_esp: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230714175052.4066150-1-robh@kernel.org Signed-off-by: Martin K. Petersen --- drivers/scsi/sun_esp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c index d06e933191a21..afa9d02a33eca 100644 --- a/drivers/scsi/sun_esp.c +++ b/drivers/scsi/sun_esp.c @@ -12,7 +12,8 @@ #include #include #include -#include +#include +#include #include #include -- GitLab From 4cf7cfa8bae11fec28785a2fec9223d0ffb25cf2 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 12 Jul 2023 11:05:11 -0700 Subject: [PATCH 0331/3445] scsi: lpfc: Pull out fw diagnostic dump log message from driver's trace buffer The firmware diagnostic dump log message does not need to be a part of the driver's log trace buffer because it is an expected user triggered event. Change LOG_TRACE_EVENT verbose flag to LOG_SLI. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20230712180522.112722-2-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 3221a934066bb..041d6f0f20971 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -2123,7 +2123,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) en_rn_msg = false; } else if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && reg_err2 == SLIPORT_ERR2_REG_FORCED_DUMP) - lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "3144 Port Down: Debug Dump\n"); else if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && reg_err2 == SLIPORT_ERR2_REG_FUNC_PROVISON) -- GitLab From 1a5cd3d073ee3f27a83846deb956f023898830fa Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 12 Jul 2023 11:05:12 -0700 Subject: [PATCH 0332/3445] scsi: lpfc: Simplify fcp_abort transport callback log message The driver is reaching into a nvme_fc_cmd_iu ptr that belongs to the transport during an abort. This could cause an unintentional ptr dereference into memory that the driver does not own. Since the nvme_fc_cmd_iu ptr was for logging purposes only, simplify the log message such that the nvme_fc_cmd_iu reference is no longer needed. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20230712180522.112722-3-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nvme.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 8db7cb99903db..3ee5cde481f31 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -1864,7 +1864,6 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, struct lpfc_nvme_fcpreq_priv *freqpriv; unsigned long flags; int ret_val; - struct nvme_fc_cmd_iu *cp; /* Validate pointers. LLDD fault handling with transport does * have timing races. @@ -1988,16 +1987,10 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, return; } - /* - * Get Command Id from cmd to plug into response. This - * code is not needed in the next NVME Transport drop. - */ - cp = (struct nvme_fc_cmd_iu *)lpfc_nbuf->nvmeCmd->cmdaddr; lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_ABTS, "6138 Transport Abort NVME Request Issued for " - "ox_id x%x nvme opcode x%x nvme cmd_id x%x\n", - nvmereq_wqe->sli4_xritag, cp->sqe.common.opcode, - cp->sqe.common.command_id); + "ox_id x%x\n", + nvmereq_wqe->sli4_xritag); return; out_unlock: -- GitLab From 869ab8b8a31c2e5f44e84df7812f7696d7331fc8 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 12 Jul 2023 11:05:13 -0700 Subject: [PATCH 0333/3445] scsi: lpfc: Remove extra ndlp kref decrement in FLOGI cmpl for loop topology In lpfc_cmpl_els_flogi(), the return out: label decrements the ndlp kref signaling that FLOGI processing on the ndlp is complete. In loop topology path, there is an unnecessary ndlp put because it also branches to the out: label. This also signals ndlp usage completion too soon. As such, remove the extra lpfc_nlp_put() when in loop topology. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20230712180522.112722-4-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 2bad9954c355f..9a7b62d184552 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1041,7 +1041,7 @@ stop_rr_fcf_flogi: !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) lpfc_nlp_put(ndlp); - lpfc_printf_vlog(vport, KERN_WARNING, LOG_TRACE_EVENT, + lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS, "0150 FLOGI failure Status:x%x/x%x " "xri x%x TMO:x%x refcnt %d\n", ulp_status, ulp_word4, cmdiocb->sli4_xritag, @@ -1091,7 +1091,6 @@ stop_rr_fcf_flogi: if (!lpfc_error_lost_link(vport, ulp_status, ulp_word4)) lpfc_issue_reg_vfi(vport); - lpfc_nlp_put(ndlp); goto out; } goto flogifail; -- GitLab From 377d7abadd74abc62c415578cda9f5e0a070abbd Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 12 Jul 2023 11:05:14 -0700 Subject: [PATCH 0334/3445] scsi: lpfc: Qualify ndlp discovery state when processing RSCN Conditionalize when to put an ndlp into recovery mode when processing RSCNs. As long as an ndlp state is beyond a PLOGI issue and has been mapped to a transport layer before, the ndlp qualifies to be put into recovery mode. Otherwise, treat the ndlp rport normally through the discovery engine. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20230712180522.112722-5-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hbadisc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 499849b58ee47..b4303254744ab 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -5757,8 +5757,11 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) (NLP_FCP_TARGET | NLP_NVME_TARGET))) return NULL; - lpfc_disc_state_machine(vport, ndlp, NULL, - NLP_EVT_DEVICE_RECOVERY); + if (ndlp->nlp_state > NLP_STE_UNUSED_NODE && + ndlp->nlp_state < NLP_STE_NPR_NODE) { + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RECOVERY); + } spin_lock_irq(&ndlp->lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; -- GitLab From 90cec07f53e9948106e335377cc249414f39684f Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 12 Jul 2023 11:05:15 -0700 Subject: [PATCH 0335/3445] scsi: lpfc: Revise ndlp kref handling for dev_loss_tmo_callbk and lpfc_drop_node The ndlp kref count implementation in lpfc_dev_loss_tmo_callbk() removes the initial node reference when a vport is unloading. When lpfc_cleanup() sends a DEVICE_RM event and is in NPR state, the driver calls lpfc_drop_node(). Subsequently, lpfc_drop_node() also removes an ndlp kref thinking it is the initial reference. This unintentionally introduces an extra kref decrement on the ndlp object. Fix by using the NLP_DROPPED node flag in lpfc_dev_loss_tmo_callbk() and lpfc_drop_node() to coordinate the removal of the initial node reference. In lpfc_dev_loss_tmo_callbk(), remove the SCSI transport reference provided the node is registered in the dev_loss context because the driver cannot call the SCSI transport in dev_loss context or afterwards. And, have lpfc_drop_node() not remove a reference if another thread is acting or has already acted on it. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20230712180522.112722-6-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hbadisc.c | 70 +++++++++++++++++++++----------- drivers/scsi/lpfc/lpfc_nvme.c | 5 ++- 2 files changed, 50 insertions(+), 25 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index b4303254744ab..388a481c81182 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -169,29 +169,44 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, "3181 dev_loss_callbk x%06x, rport x%px flg x%x " - "load_flag x%x refcnt %d state %d xpt x%x\n", + "load_flag x%x refcnt %u state %d xpt x%x\n", ndlp->nlp_DID, ndlp->rport, ndlp->nlp_flag, vport->load_flag, kref_read(&ndlp->kref), ndlp->nlp_state, ndlp->fc4_xpt_flags); - /* Don't schedule a worker thread event if the vport is going down. - * The teardown process cleans up the node via lpfc_drop_node. - */ + /* Don't schedule a worker thread event if the vport is going down. */ if (vport->load_flag & FC_UNLOADING) { - ((struct lpfc_rport_data *)rport->dd_data)->pnode = NULL; + spin_lock_irqsave(&ndlp->lock, iflags); ndlp->rport = NULL; - ndlp->fc4_xpt_flags &= ~SCSI_XPT_REGD; - /* clear the NLP_XPT_REGD if the node is not registered - * with nvme-fc + /* The scsi_transport is done with the rport so lpfc cannot + * call to unregister. Remove the scsi transport reference + * and clean up the SCSI transport node details. */ - if (ndlp->fc4_xpt_flags == NLP_XPT_REGD) - ndlp->fc4_xpt_flags &= ~NLP_XPT_REGD; + if (ndlp->fc4_xpt_flags & (NLP_XPT_REGD | SCSI_XPT_REGD)) { + ndlp->fc4_xpt_flags &= ~SCSI_XPT_REGD; - /* Remove the node reference from remote_port_add now. - * The driver will not call remote_port_delete. + /* NVME transport-registered rports need the + * NLP_XPT_REGD flag to complete an unregister. + */ + if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD)) + ndlp->fc4_xpt_flags &= ~NLP_XPT_REGD; + spin_unlock_irqrestore(&ndlp->lock, iflags); + lpfc_nlp_put(ndlp); + spin_lock_irqsave(&ndlp->lock, iflags); + } + + /* Only 1 thread can drop the initial node reference. If + * another thread has set NLP_DROPPED, this thread is done. */ - lpfc_nlp_put(ndlp); + if (!(ndlp->nlp_flag & NLP_DROPPED)) { + ndlp->nlp_flag |= NLP_DROPPED; + spin_unlock_irqrestore(&ndlp->lock, iflags); + lpfc_nlp_put(ndlp); + spin_lock_irqsave(&ndlp->lock, iflags); + } + + spin_unlock_irqrestore(&ndlp->lock, iflags); return; } @@ -4686,7 +4701,8 @@ lpfc_nlp_unreg_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) spin_lock_irqsave(&ndlp->lock, iflags); if (!(ndlp->fc4_xpt_flags & NLP_XPT_REGD)) { spin_unlock_irqrestore(&ndlp->lock, iflags); - lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, + lpfc_printf_vlog(vport, KERN_INFO, + LOG_ELS | LOG_NODE | LOG_DISCOVERY, "0999 %s Not regd: ndlp x%px rport x%px DID " "x%x FLG x%x XPT x%x\n", __func__, ndlp, ndlp->rport, ndlp->nlp_DID, @@ -4702,9 +4718,10 @@ lpfc_nlp_unreg_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) vport->phba->nport_event_cnt++; lpfc_unregister_remote_port(ndlp); } else if (!ndlp->rport) { - lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, + lpfc_printf_vlog(vport, KERN_INFO, + LOG_ELS | LOG_NODE | LOG_DISCOVERY, "1999 %s NDLP in devloss x%px DID x%x FLG x%x" - " XPT x%x refcnt %d\n", + " XPT x%x refcnt %u\n", __func__, ndlp, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->fc4_xpt_flags, kref_read(&ndlp->kref)); @@ -4954,22 +4971,29 @@ lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { /* * Use of lpfc_drop_node and UNUSED list: lpfc_drop_node should - * be used if we wish to issue the "last" lpfc_nlp_put() to remove - * the ndlp from the vport. The ndlp marked as UNUSED on the list - * until ALL other outstanding threads have completed. We check - * that the ndlp not already in the UNUSED state before we proceed. + * be used when lpfc wants to remove the "last" lpfc_nlp_put() to + * release the ndlp from the vport when conditions are correct. */ if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) return; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); - ndlp->nlp_flag |= NLP_DROPPED; if (vport->phba->sli_rev == LPFC_SLI_REV4) { lpfc_cleanup_vports_rrqs(vport, ndlp); lpfc_unreg_rpi(vport, ndlp); } - lpfc_nlp_put(ndlp); - return; + /* NLP_DROPPED means another thread already removed the initial + * reference from lpfc_nlp_init. If set, don't drop it again and + * introduce an imbalance. + */ + spin_lock_irq(&ndlp->lock); + if (!(ndlp->nlp_flag & NLP_DROPPED)) { + ndlp->nlp_flag |= NLP_DROPPED; + spin_unlock_irq(&ndlp->lock); + lpfc_nlp_put(ndlp); + return; + } + spin_unlock_irq(&ndlp->lock); } /* diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 3ee5cde481f31..39acbcb7ec66a 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -2503,8 +2503,9 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6031 RemotePort Registration failed " - "err: %d, DID x%06x\n", - ret, ndlp->nlp_DID); + "err: %d, DID x%06x ref %u\n", + ret, ndlp->nlp_DID, kref_read(&ndlp->kref)); + lpfc_nlp_put(ndlp); } return ret; -- GitLab From 04c3200114921ba7223997dc61ddeedc6f581991 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 12 Jul 2023 11:05:16 -0700 Subject: [PATCH 0336/3445] scsi: lpfc: Set Establish Image Pair service parameter only for Target Functions Previously, Establish Image Pair was set in all PRLI_ACC responses regardless if the received PRLI was from an initiator or target function. Specific target vendors that can operate in both initiator and target mode, may view the PRLI_ACC with Establish Image Pair set as an invalid service parameter when operating in initiator only mode. This causes discovery issues later when the target switches on its target mode function. Revise logic that determines an rport's role as an initiator or target and set the Establish Image Pair service parameter bit only if the Target Function bit is set. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20230712180522.112722-7-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 16 +++++++++++- drivers/scsi/lpfc/lpfc_hw.h | 2 ++ drivers/scsi/lpfc/lpfc_nportdisc.c | 39 +++++++++++++++++++----------- 3 files changed, 42 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 9a7b62d184552..aa48153c37352 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -6165,11 +6165,25 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, npr->TaskRetryIdReq = 1; } npr->acceptRspCode = PRLI_REQ_EXECUTED; - npr->estabImagePair = 1; + + /* Set image pair for complementary pairs only. */ + if (ndlp->nlp_type & NLP_FCP_TARGET) + npr->estabImagePair = 1; + else + npr->estabImagePair = 0; npr->readXferRdyDis = 1; npr->ConfmComplAllowed = 1; npr->prliType = PRLI_FCP_TYPE; npr->initiatorFunc = 1; + + /* Xmit PRLI ACC response tag */ + lpfc_printf_vlog(vport, KERN_INFO, + LOG_ELS | LOG_NODE | LOG_DISCOVERY, + "6014 FCP issue PRLI ACC imgpair %d " + "retry %d task %d\n", + npr->estabImagePair, + npr->Retry, npr->TaskRetryIdReq); + } else if (prli_fc4_req == PRLI_NVME_TYPE) { /* Respond with an NVME PRLI Type */ npr_nvme = (struct lpfc_nvme_prli *) pcmd; diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index aaea3e31944d0..2108b4cb78157 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -764,6 +764,8 @@ typedef struct _PRLI { /* Structure is in Big Endian format */ #define PRLI_PREDEF_CONFIG 0x5 #define PRLI_PARTIAL_SUCCESS 0x6 #define PRLI_INVALID_PAGE_CNT 0x7 +#define PRLI_INV_SRV_PARM 0x8 + uint8_t word0Reserved3; /* FC Parm Word 0, bit 0:7 */ uint32_t origProcAssoc; /* FC Parm Word 1, bit 0:31 */ diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index b86ff9fcdf0c6..6261560eb512f 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -2148,6 +2148,7 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct lpfc_nvme_prli *nvpr; void *temp_ptr; u32 ulp_status; + bool acc_imode_sps = false; cmdiocb = (struct lpfc_iocbq *) arg; rspiocb = cmdiocb->rsp_iocb; @@ -2182,22 +2183,32 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, goto out_err; } - if (npr && (npr->acceptRspCode == PRLI_REQ_EXECUTED) && - (npr->prliType == PRLI_FCP_TYPE)) { - lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, - "6028 FCP NPR PRLI Cmpl Init %d Target %d\n", - npr->initiatorFunc, - npr->targetFunc); - if (npr->initiatorFunc) - ndlp->nlp_type |= NLP_FCP_INITIATOR; - if (npr->targetFunc) { - ndlp->nlp_type |= NLP_FCP_TARGET; - if (npr->writeXferRdyDis) - ndlp->nlp_flag |= NLP_FIRSTBURST; + if (npr && npr->prliType == PRLI_FCP_TYPE) { + lpfc_printf_vlog(vport, KERN_INFO, + LOG_ELS | LOG_NODE | LOG_DISCOVERY, + "6028 FCP NPR PRLI Cmpl Init %d Target %d " + "EIP %d AccCode x%x\n", + npr->initiatorFunc, npr->targetFunc, + npr->estabImagePair, npr->acceptRspCode); + + if (npr->acceptRspCode == PRLI_INV_SRV_PARM) { + /* Strict initiators don't establish an image pair. */ + if (npr->initiatorFunc && !npr->targetFunc && + !npr->estabImagePair) + acc_imode_sps = true; } - if (npr->Retry) - ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE; + if (npr->acceptRspCode == PRLI_REQ_EXECUTED || acc_imode_sps) { + if (npr->initiatorFunc) + ndlp->nlp_type |= NLP_FCP_INITIATOR; + if (npr->targetFunc) { + ndlp->nlp_type |= NLP_FCP_TARGET; + if (npr->writeXferRdyDis) + ndlp->nlp_flag |= NLP_FIRSTBURST; + } + if (npr->Retry) + ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE; + } } else if (nvpr && (bf_get_be32(prli_acc_rsp_code, nvpr) == PRLI_REQ_EXECUTED) && -- GitLab From 9388da30376670613d7b8031e6d62b0b6ce08228 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 12 Jul 2023 11:05:17 -0700 Subject: [PATCH 0337/3445] scsi: lpfc: Make fabric zone discovery more robust when handling unsolicited LOGO This patch provides better target rport recovery when a target rport is running in initiator mode to discover the fabric. Such a target will issue a LOGO before switching back to strict target mode and changes are made to recover the login. Log messages are also updated accordingly. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20230712180522.112722-8-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_ct.c | 20 +++++++---- drivers/scsi/lpfc/lpfc_els.c | 14 ++++---- drivers/scsi/lpfc/lpfc_nportdisc.c | 53 ++++++++++++++++-------------- 3 files changed, 50 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 474834f313a7b..baae1f8279e0c 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1557,7 +1557,8 @@ lpfc_cmpl_ct_cmd_gft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ndlp->nlp_fc4_type |= NLP_FC4_FCP; if (fc4_data_1 & LPFC_FC4_TYPE_BITMASK) ndlp->nlp_fc4_type |= NLP_FC4_NVME; - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_INFO, + LOG_DISCOVERY | LOG_NODE, "3064 Setting ndlp x%px, DID x%06x " "with FC4 x%08x, Data: x%08x x%08x " "%d\n", @@ -1568,14 +1569,21 @@ lpfc_cmpl_ct_cmd_gft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (ndlp->nlp_state == NLP_STE_REG_LOGIN_ISSUE && ndlp->nlp_fc4_type) { ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; - - lpfc_nlp_set_state(vport, ndlp, - NLP_STE_PRLI_ISSUE); - lpfc_issue_els_prli(vport, ndlp, 0); + /* This is a fabric topology so if discovery + * started with an unsolicited PLOGI, don't + * send a PRLI. Targets don't issue PLOGI or + * PRLI when acting as a target. Likely this is + * an initiator function. + */ + if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) { + lpfc_nlp_set_state(vport, ndlp, + NLP_STE_PRLI_ISSUE); + lpfc_issue_els_prli(vport, ndlp, 0); + } } else if (!ndlp->nlp_fc4_type) { /* If fc4 type is still unknown, then LOGO */ lpfc_printf_vlog(vport, KERN_INFO, - LOG_DISCOVERY, + LOG_DISCOVERY | LOG_NODE, "6443 Sending LOGO ndlp x%px," "DID x%06x with fc4_type: " "x%08x, state: %d\n", diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index aa48153c37352..f37757449f3c3 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -2376,10 +2376,10 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* PRLI failed */ lpfc_printf_vlog(vport, mode, loglevel, "2754 PRLI failure DID:%06X Status:x%x/x%x, " - "data: x%x x%x\n", + "data: x%x x%x x%x\n", ndlp->nlp_DID, ulp_status, ulp_word4, ndlp->nlp_state, - ndlp->fc4_prli_sent); + ndlp->fc4_prli_sent, ndlp->nlp_flag); /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ if (!lpfc_error_lost_link(vport, ulp_status, ulp_word4)) @@ -2390,14 +2390,16 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * mismatch typically caused by an RSCN. Skip any * processing to allow recovery. */ - if (ndlp->nlp_state >= NLP_STE_PLOGI_ISSUE && - ndlp->nlp_state <= NLP_STE_REG_LOGIN_ISSUE) { + if ((ndlp->nlp_state >= NLP_STE_PLOGI_ISSUE && + ndlp->nlp_state <= NLP_STE_REG_LOGIN_ISSUE) || + (ndlp->nlp_state == NLP_STE_NPR_NODE && + ndlp->nlp_flag & NLP_DELAY_TMO)) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "2784 PRLI cmpl: state mismatch " + "2784 PRLI cmpl: Allow Node recovery " "DID x%06x nstate x%x nflag x%x\n", ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag); - goto out; + goto out; } /* diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 6261560eb512f..8f64244873973 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -879,23 +879,34 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, spin_unlock_irq(shost->host_lock); lpfc_retry_pport_discovery(phba); } - } else if ((!(ndlp->nlp_type & NLP_FABRIC) && - ((ndlp->nlp_type & NLP_FCP_TARGET) || - (ndlp->nlp_type & NLP_NVME_TARGET) || - (vport->fc_flag & FC_PT2PT))) || - (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) { - /* Only try to re-login if this is NOT a Fabric Node - * AND the remote NPORT is a FCP/NVME Target or we - * are in pt2pt mode. NLP_STE_ADISC_ISSUE is a special - * case for LOGO as a response to ADISC behavior. - */ - mod_timer(&ndlp->nlp_delayfunc, - jiffies + msecs_to_jiffies(1000 * 1)); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(&ndlp->lock); - - ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; + } else { + lpfc_printf_vlog(vport, KERN_INFO, + LOG_NODE | LOG_ELS | LOG_DISCOVERY, + "3203 LOGO recover nport x%06x state x%x " + "ntype x%x fc_flag x%x\n", + ndlp->nlp_DID, ndlp->nlp_state, + ndlp->nlp_type, vport->fc_flag); + + /* Special cases for rports that recover post LOGO. */ + if ((!(ndlp->nlp_type == NLP_FABRIC) && + (ndlp->nlp_type & (NLP_FCP_TARGET | NLP_NVME_TARGET) || + vport->fc_flag & FC_PT2PT)) || + (ndlp->nlp_state >= NLP_STE_ADISC_ISSUE || + ndlp->nlp_state <= NLP_STE_PRLI_ISSUE)) { + mod_timer(&ndlp->nlp_delayfunc, + jiffies + msecs_to_jiffies(1000 * 1)); + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag |= NLP_DELAY_TMO; + spin_unlock_irq(&ndlp->lock); + ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; + lpfc_printf_vlog(vport, KERN_INFO, + LOG_NODE | LOG_ELS | LOG_DISCOVERY, + "3204 Start nlpdelay on DID x%06x " + "nflag x%x lastels x%x ref cnt %u", + ndlp->nlp_DID, ndlp->nlp_flag, + ndlp->nlp_last_elscmd, + kref_read(&ndlp->kref)); + } } out: /* Unregister from backend, could have been skipped due to ADISC */ @@ -1854,7 +1865,6 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; LPFC_MBOXQ_t *mb; LPFC_MBOXQ_t *nextmb; - struct lpfc_nodelist *ns_ndlp; cmdiocb = (struct lpfc_iocbq *) arg; @@ -1882,13 +1892,6 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport, } spin_unlock_irq(&phba->hbalock); - /* software abort if any GID_FT is outstanding */ - if (vport->cfg_enable_fc4_type != LPFC_ENABLE_FCP) { - ns_ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (ns_ndlp) - lpfc_els_abort(phba, ns_ndlp); - } - lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO); return ndlp->nlp_state; } -- GitLab From 089ea22e374aa20043e72243c47b5867d5419d38 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 12 Jul 2023 11:05:18 -0700 Subject: [PATCH 0338/3445] scsi: lpfc: Abort outstanding ELS cmds when mailbox timeout error is detected A mailbox timeout error usually indicates something has gone wrong, and a follow up reset of the HBA is a typical recovery mechanism. Introduce a MBX_TMO_ERR flag to detect such cases and have lpfc_els_flush_cmd abort ELS commands if the MBX_TMO_ERR flag condition was set. This ensures all of the registered SGL resources meant for ELS traffic are not leaked after an HBA reset. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20230712180522.112722-9-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 1 + drivers/scsi/lpfc/lpfc_els.c | 25 ++++++++++++++++++------- drivers/scsi/lpfc/lpfc_init.c | 20 +++++++++++++++++--- drivers/scsi/lpfc/lpfc_sli.c | 8 +++++++- 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 9a89636843693..e8d7eeeb21856 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -872,6 +872,7 @@ enum lpfc_irq_chann_mode { enum lpfc_hba_bit_flags { FABRIC_COMANDS_BLOCKED, HBA_PCI_ERR, + MBX_TMO_ERR, }; struct lpfc_hba { diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index f37757449f3c3..b5cd6d1c0a5ae 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -9603,11 +9603,13 @@ void lpfc_els_flush_cmd(struct lpfc_vport *vport) { LIST_HEAD(abort_list); + LIST_HEAD(cancel_list); struct lpfc_hba *phba = vport->phba; struct lpfc_sli_ring *pring; struct lpfc_iocbq *tmp_iocb, *piocb; u32 ulp_command; unsigned long iflags = 0; + bool mbx_tmo_err; lpfc_fabric_abort_vport(vport); @@ -9629,15 +9631,16 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) if (phba->sli_rev == LPFC_SLI_REV4) spin_lock(&pring->ring_lock); + mbx_tmo_err = test_bit(MBX_TMO_ERR, &phba->bit_flags); /* First we need to issue aborts to outstanding cmds on txcmpl */ list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { - if (piocb->cmd_flag & LPFC_IO_LIBDFC) + if (piocb->cmd_flag & LPFC_IO_LIBDFC && !mbx_tmo_err) continue; if (piocb->vport != vport) continue; - if (piocb->cmd_flag & LPFC_DRIVER_ABORTED) + if (piocb->cmd_flag & LPFC_DRIVER_ABORTED && !mbx_tmo_err) continue; /* On the ELS ring we can have ELS_REQUESTs or @@ -9656,8 +9659,8 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) */ if (phba->link_state == LPFC_LINK_DOWN) piocb->cmd_cmpl = lpfc_cmpl_els_link_down; - } - if (ulp_command == CMD_GEN_REQUEST64_CR) + } else if (ulp_command == CMD_GEN_REQUEST64_CR || + mbx_tmo_err) list_add_tail(&piocb->dlist, &abort_list); } @@ -9669,11 +9672,19 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) { spin_lock_irqsave(&phba->hbalock, iflags); list_del_init(&piocb->dlist); - lpfc_sli_issue_abort_iotag(phba, pring, piocb, NULL); + if (mbx_tmo_err) + list_move_tail(&piocb->list, &cancel_list); + else + lpfc_sli_issue_abort_iotag(phba, pring, piocb, NULL); + spin_unlock_irqrestore(&phba->hbalock, iflags); } - /* Make sure HBA is alive */ - lpfc_issue_hb_tmo(phba); + if (!list_empty(&cancel_list)) + lpfc_sli_cancel_iocbs(phba, &cancel_list, IOSTAT_LOCAL_REJECT, + IOERR_SLI_ABORTED); + else + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); if (!list_empty(&abort_list)) lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 041d6f0f20971..c878fb99dc4c1 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -7550,6 +7550,8 @@ lpfc_disable_pci_dev(struct lpfc_hba *phba) void lpfc_reset_hba(struct lpfc_hba *phba) { + int rc = 0; + /* If resets are disabled then set error state and return. */ if (!phba->cfg_enable_hba_reset) { phba->link_state = LPFC_HBA_ERROR; @@ -7560,13 +7562,25 @@ lpfc_reset_hba(struct lpfc_hba *phba) if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) { lpfc_offline_prep(phba, LPFC_MBX_WAIT); } else { + if (test_bit(MBX_TMO_ERR, &phba->bit_flags)) { + /* Perform a PCI function reset to start from clean */ + rc = lpfc_pci_function_reset(phba); + lpfc_els_flush_all_cmd(phba); + } lpfc_offline_prep(phba, LPFC_MBX_NO_WAIT); lpfc_sli_flush_io_rings(phba); } lpfc_offline(phba); - lpfc_sli_brdrestart(phba); - lpfc_online(phba); - lpfc_unblock_mgmt_io(phba); + clear_bit(MBX_TMO_ERR, &phba->bit_flags); + if (unlikely(rc)) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "8888 PCI function reset failed rc %x\n", + rc); + } else { + lpfc_sli_brdrestart(phba); + lpfc_online(phba); + lpfc_unblock_mgmt_io(phba); + } } /** diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 58d10f8f75a78..4dfadf254a727 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -3935,6 +3935,8 @@ void lpfc_poll_eratt(struct timer_list *t) uint64_t sli_intr, cnt; phba = from_timer(phba, t, eratt_poll); + if (!(phba->hba_flag & HBA_SETUP)) + return; /* Here we will also keep track of interrupts per sec of the hba */ sli_intr = phba->sli.slistat.sli_intr; @@ -7693,7 +7695,9 @@ lpfc_sli4_repost_sgl_list(struct lpfc_hba *phba, spin_unlock_irq(&phba->hbalock); } else { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, - "3161 Failure to post sgl to port.\n"); + "3161 Failure to post sgl to port,status %x " + "blkcnt %d totalcnt %d postcnt %d\n", + status, block_cnt, total_cnt, post_cnt); return -EIO; } @@ -8478,6 +8482,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) spin_unlock_irq(&phba->hbalock); } } + phba->hba_flag &= ~HBA_SETUP; lpfc_sli4_dip(phba); @@ -9282,6 +9287,7 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) * would get IOCB_ERROR from lpfc_sli_issue_iocb, allowing * it to fail all outstanding SCSI IO. */ + set_bit(MBX_TMO_ERR, &phba->bit_flags); spin_lock_irq(&phba->pport->work_port_lock); phba->pport->work_port_events &= ~WORKER_MBOX_TMO; spin_unlock_irq(&phba->pport->work_port_lock); -- GitLab From d668b368efc2fca15bf785c44b449d38d6b50553 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 12 Jul 2023 11:05:19 -0700 Subject: [PATCH 0339/3445] scsi: lpfc: Refactor cpu affinity assignment paths During initialization, a lot of the same logic is used on MSI-X vector CPU affinity assignment. Create a lpfc_next_present_cpu() helper routine, and apply its usage for refactoring purposes. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20230712180522.112722-10-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 19 +++++++++++++++++++ drivers/scsi/lpfc/lpfc_init.c | 31 +++++++------------------------ drivers/scsi/lpfc/lpfc_nvmet.c | 5 +---- 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index e8d7eeeb21856..bc1c5f6df0908 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1709,6 +1709,25 @@ lpfc_next_online_cpu(const struct cpumask *mask, unsigned int start) return cpu_it; } +/** + * lpfc_next_present_cpu - Finds next present CPU after n + * @n: the cpu prior to search + * + * Note: If no next present cpu, then fallback to first present cpu. + * + **/ +static inline unsigned int lpfc_next_present_cpu(int n) +{ + unsigned int cpu; + + cpu = cpumask_next(n, cpu_present_mask); + + if (cpu >= nr_cpu_ids) + cpu = cpumask_first(cpu_present_mask); + + return cpu; +} + /** * lpfc_sli4_mod_hba_eq_delay - update EQ delay * @phba: Pointer to HBA context object. diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index c878fb99dc4c1..9e59c050103d6 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -12512,10 +12512,7 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors) (new_cpup->eq != LPFC_VECTOR_MAP_EMPTY) && (new_cpup->phys_id == cpup->phys_id)) goto found_same; - new_cpu = cpumask_next( - new_cpu, cpu_present_mask); - if (new_cpu >= nr_cpu_ids) - new_cpu = first_cpu; + new_cpu = lpfc_next_present_cpu(new_cpu); } /* At this point, we leave the CPU as unassigned */ continue; @@ -12527,9 +12524,7 @@ found_same: * chance of having multiple unassigned CPU entries * selecting the same IRQ. */ - start_cpu = cpumask_next(new_cpu, cpu_present_mask); - if (start_cpu >= nr_cpu_ids) - start_cpu = first_cpu; + start_cpu = lpfc_next_present_cpu(new_cpu); lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "3337 Set Affinity: CPU %d " @@ -12562,10 +12557,7 @@ found_same: if (!(new_cpup->flag & LPFC_CPU_MAP_UNASSIGN) && (new_cpup->eq != LPFC_VECTOR_MAP_EMPTY)) goto found_any; - new_cpu = cpumask_next( - new_cpu, cpu_present_mask); - if (new_cpu >= nr_cpu_ids) - new_cpu = first_cpu; + new_cpu = lpfc_next_present_cpu(new_cpu); } /* We should never leave an entry unassigned */ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -12581,9 +12573,7 @@ found_any: * chance of having multiple unassigned CPU entries * selecting the same IRQ. */ - start_cpu = cpumask_next(new_cpu, cpu_present_mask); - if (start_cpu >= nr_cpu_ids) - start_cpu = first_cpu; + start_cpu = lpfc_next_present_cpu(new_cpu); lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "3338 Set Affinity: CPU %d " @@ -12654,9 +12644,7 @@ found_any: new_cpup->core_id == cpup->core_id) { goto found_hdwq; } - new_cpu = cpumask_next(new_cpu, cpu_present_mask); - if (new_cpu >= nr_cpu_ids) - new_cpu = first_cpu; + new_cpu = lpfc_next_present_cpu(new_cpu); } /* If we can't match both phys_id and core_id, @@ -12668,10 +12656,7 @@ found_any: if (new_cpup->hdwq != LPFC_VECTOR_MAP_EMPTY && new_cpup->phys_id == cpup->phys_id) goto found_hdwq; - - new_cpu = cpumask_next(new_cpu, cpu_present_mask); - if (new_cpu >= nr_cpu_ids) - new_cpu = first_cpu; + new_cpu = lpfc_next_present_cpu(new_cpu); } /* Otherwise just round robin on cfg_hdw_queue */ @@ -12680,9 +12665,7 @@ found_any: goto logit; found_hdwq: /* We found an available entry, copy the IRQ info */ - start_cpu = cpumask_next(new_cpu, cpu_present_mask); - if (start_cpu >= nr_cpu_ids) - start_cpu = first_cpu; + start_cpu = lpfc_next_present_cpu(new_cpu); cpup->hdwq = new_cpup->hdwq; logit: lpfc_printf_log(phba, KERN_INFO, LOG_INIT, diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index dff4584d338ba..425328d9c2d80 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -1620,10 +1620,7 @@ lpfc_nvmet_setup_io_context(struct lpfc_hba *phba) cpu = cpumask_first(cpu_present_mask); continue; } - cpu = cpumask_next(cpu, cpu_present_mask); - if (cpu == nr_cpu_ids) - cpu = cpumask_first(cpu_present_mask); - + cpu = lpfc_next_present_cpu(cpu); } for_each_present_cpu(i) { -- GitLab From 81907422cac08161cf1a351c416c1f891ff4af57 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 12 Jul 2023 11:05:20 -0700 Subject: [PATCH 0340/3445] scsi: lpfc: Clean up SLI-4 sysfs resource reporting Currently, we have dated logic to work around the differences between SLI-4 and SLI-3 resource reporting through sysfs. Leave the SLI-3 path untouched, but for SLI4 path, retrieve resource values from the phba->sli4_hba->max_cfg_param structure. Max values are populated during ACQE events right after READ_CONFIG mbox cmd is sent. Instead of the dated subtraction logic, used resource calculation is directly fed into sysfs for display. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20230712180522.112722-11-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 136 +++++++++++++++++++++++++--------- 1 file changed, 101 insertions(+), 35 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 21c7ecd3ede55..b1c9107d34083 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -2127,11 +2127,12 @@ lpfc_get_hba_info(struct lpfc_hba *phba, uint32_t *mrpi, uint32_t *arpi, uint32_t *mvpi, uint32_t *avpi) { - struct lpfc_mbx_read_config *rd_config; LPFC_MBOXQ_t *pmboxq; MAILBOX_t *pmb; int rc = 0; - uint32_t max_vpi; + struct lpfc_sli4_hba *sli4_hba; + struct lpfc_max_cfg_param *max_cfg_param; + u16 rsrc_ext_cnt, rsrc_ext_size, max_vpi; /* * prevent udev from issuing mailbox commands until the port is @@ -2167,31 +2168,65 @@ lpfc_get_hba_info(struct lpfc_hba *phba, } if (phba->sli_rev == LPFC_SLI_REV4) { - rd_config = &pmboxq->u.mqe.un.rd_config; - if (mrpi) - *mrpi = bf_get(lpfc_mbx_rd_conf_rpi_count, rd_config); - if (arpi) - *arpi = bf_get(lpfc_mbx_rd_conf_rpi_count, rd_config) - - phba->sli4_hba.max_cfg_param.rpi_used; - if (mxri) - *mxri = bf_get(lpfc_mbx_rd_conf_xri_count, rd_config); - if (axri) - *axri = bf_get(lpfc_mbx_rd_conf_xri_count, rd_config) - - phba->sli4_hba.max_cfg_param.xri_used; + sli4_hba = &phba->sli4_hba; + max_cfg_param = &sli4_hba->max_cfg_param; + + /* Normally, extents are not used */ + if (!phba->sli4_hba.extents_in_use) { + if (mrpi) + *mrpi = max_cfg_param->max_rpi; + if (mxri) + *mxri = max_cfg_param->max_xri; + if (mvpi) { + max_vpi = max_cfg_param->max_vpi; + + /* Limit the max we support */ + if (max_vpi > LPFC_MAX_VPI) + max_vpi = LPFC_MAX_VPI; + *mvpi = max_vpi; + } + } else { /* Extents in use */ + if (mrpi) { + if (lpfc_sli4_get_avail_extnt_rsrc(phba, + LPFC_RSC_TYPE_FCOE_RPI, + &rsrc_ext_cnt, + &rsrc_ext_size)) { + rc = 0; + goto free_pmboxq; + } + + *mrpi = rsrc_ext_cnt * rsrc_ext_size; + } - /* Account for differences with SLI-3. Get vpi count from - * mailbox data and subtract one for max vpi value. - */ - max_vpi = (bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) > 0) ? - (bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) - 1) : 0; + if (mxri) { + if (lpfc_sli4_get_avail_extnt_rsrc(phba, + LPFC_RSC_TYPE_FCOE_XRI, + &rsrc_ext_cnt, + &rsrc_ext_size)) { + rc = 0; + goto free_pmboxq; + } - /* Limit the max we support */ - if (max_vpi > LPFC_MAX_VPI) - max_vpi = LPFC_MAX_VPI; - if (mvpi) - *mvpi = max_vpi; - if (avpi) - *avpi = max_vpi - phba->sli4_hba.max_cfg_param.vpi_used; + *mxri = rsrc_ext_cnt * rsrc_ext_size; + } + + if (mvpi) { + if (lpfc_sli4_get_avail_extnt_rsrc(phba, + LPFC_RSC_TYPE_FCOE_VPI, + &rsrc_ext_cnt, + &rsrc_ext_size)) { + rc = 0; + goto free_pmboxq; + } + + max_vpi = rsrc_ext_cnt * rsrc_ext_size; + + /* Limit the max we support */ + if (max_vpi > LPFC_MAX_VPI) + max_vpi = LPFC_MAX_VPI; + *mvpi = max_vpi; + } + } } else { if (mrpi) *mrpi = pmb->un.varRdConfig.max_rpi; @@ -2212,8 +2247,12 @@ lpfc_get_hba_info(struct lpfc_hba *phba, } } + /* Success */ + rc = 1; + +free_pmboxq: mempool_free(pmboxq, phba->mbox_mem_pool); - return 1; + return rc; } /** @@ -2265,10 +2304,19 @@ lpfc_used_rpi_show(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - uint32_t cnt, acnt; + struct lpfc_sli4_hba *sli4_hba; + struct lpfc_max_cfg_param *max_cfg_param; + u32 cnt = 0, acnt = 0; - if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, &acnt, NULL, NULL)) - return scnprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt)); + if (phba->sli_rev == LPFC_SLI_REV4) { + sli4_hba = &phba->sli4_hba; + max_cfg_param = &sli4_hba->max_cfg_param; + return scnprintf(buf, PAGE_SIZE, "%d\n", + max_cfg_param->rpi_used); + } else { + if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, &acnt, NULL, NULL)) + return scnprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt)); + } return scnprintf(buf, PAGE_SIZE, "Unknown\n"); } @@ -2321,10 +2369,19 @@ lpfc_used_xri_show(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - uint32_t cnt, acnt; + struct lpfc_sli4_hba *sli4_hba; + struct lpfc_max_cfg_param *max_cfg_param; + u32 cnt = 0, acnt = 0; - if (lpfc_get_hba_info(phba, &cnt, &acnt, NULL, NULL, NULL, NULL)) - return scnprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt)); + if (phba->sli_rev == LPFC_SLI_REV4) { + sli4_hba = &phba->sli4_hba; + max_cfg_param = &sli4_hba->max_cfg_param; + return scnprintf(buf, PAGE_SIZE, "%d\n", + max_cfg_param->xri_used); + } else { + if (lpfc_get_hba_info(phba, &cnt, &acnt, NULL, NULL, NULL, NULL)) + return scnprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt)); + } return scnprintf(buf, PAGE_SIZE, "Unknown\n"); } @@ -2377,10 +2434,19 @@ lpfc_used_vpi_show(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - uint32_t cnt, acnt; + struct lpfc_sli4_hba *sli4_hba; + struct lpfc_max_cfg_param *max_cfg_param; + u32 cnt = 0, acnt = 0; - if (lpfc_get_hba_info(phba, NULL, NULL, NULL, NULL, &cnt, &acnt)) - return scnprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt)); + if (phba->sli_rev == LPFC_SLI_REV4) { + sli4_hba = &phba->sli4_hba; + max_cfg_param = &sli4_hba->max_cfg_param; + return scnprintf(buf, PAGE_SIZE, "%d\n", + max_cfg_param->vpi_used); + } else { + if (lpfc_get_hba_info(phba, NULL, NULL, NULL, NULL, &cnt, &acnt)) + return scnprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt)); + } return scnprintf(buf, PAGE_SIZE, "Unknown\n"); } -- GitLab From cfb9b8f506d5e8bc4765c83c5910511699da19d8 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 12 Jul 2023 11:05:21 -0700 Subject: [PATCH 0341/3445] scsi: lpfc: Update lpfc version to 14.2.0.14 Update lpfc version to 14.2.0.14 Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20230712180522.112722-12-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 6f35491aed0fd..13a547277f97f 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -20,7 +20,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "14.2.0.13" +#define LPFC_DRIVER_VERSION "14.2.0.14" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ -- GitLab From 71fe5ddac546d93b5b6ba36020cb7d7ae0900c20 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Wed, 12 Jul 2023 11:05:22 -0700 Subject: [PATCH 0342/3445] scsi: lpfc: Copyright updates for 14.2.0.14 patches Update copyrights to 2023 for files modified in the 14.2.0.14 patch set. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20230712180522.112722-13-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nportdisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 8f64244873973..1eb7f7e60bba5 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * -- GitLab From 6dfe4344c168c6ca20fe7640649aacfcefcccb26 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 14 Jul 2023 12:30:55 +0530 Subject: [PATCH 0343/3445] scsi: qla2xxx: Fix deletion race condition System crash when using debug kernel due to link list corruption. The cause of the link list corruption is due to session deletion was allowed to queue up twice. Here's the internal trace that show the same port was allowed to double queue for deletion on different cpu. 20808683956 015 qla2xxx [0000:13:00.1]-e801:4: Scheduling sess ffff93ebf9306800 for deletion 50:06:0e:80:12:48:ff:50 fc4_type 1 20808683957 027 qla2xxx [0000:13:00.1]-e801:4: Scheduling sess ffff93ebf9306800 for deletion 50:06:0e:80:12:48:ff:50 fc4_type 1 Move the clearing/setting of deleted flag lock. Cc: stable@vger.kernel.org Fixes: 726b85487067 ("qla2xxx: Add framework for async fabric discovery") Signed-off-by: Quinn Tran Signed-off-by: Nilesh Javali Link: https://lore.kernel.org/r/20230714070104.40052-2-njavali@marvell.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 16 ++++++++++++++-- drivers/scsi/qla2xxx/qla_target.c | 14 +++++++------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index c3dd8dd4f7340..5c2a646265e4c 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -508,6 +508,7 @@ static void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea) { struct fc_port *fcport = ea->fcport; + unsigned long flags; ql_dbg(ql_dbg_disc, vha, 0x20d2, "%s %8phC DS %d LS %d rc %d login %d|%d rscn %d|%d lid %d\n", @@ -522,9 +523,15 @@ void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea) ql_dbg(ql_dbg_disc, vha, 0x2066, "%s %8phC: adisc fail: post delete\n", __func__, ea->fcport->port_name); + + spin_lock_irqsave(&vha->work_lock, flags); /* deleted = 0 & logout_on_delete = force fw cleanup */ - fcport->deleted = 0; + if (fcport->deleted == QLA_SESS_DELETED) + fcport->deleted = 0; + fcport->logout_on_delete = 1; + spin_unlock_irqrestore(&vha->work_lock, flags); + qlt_schedule_sess_for_deletion(ea->fcport); return; } @@ -1446,7 +1453,6 @@ void __qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); ea->fcport->login_gen++; - ea->fcport->deleted = 0; ea->fcport->logout_on_delete = 1; if (!ea->fcport->login_succ && !IS_SW_RESV_ADDR(ea->fcport->d_id)) { @@ -6090,6 +6096,8 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport) void qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) { + unsigned long flags; + if (IS_SW_RESV_ADDR(fcport->d_id)) return; @@ -6099,7 +6107,11 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) qla2x00_set_fcport_disc_state(fcport, DSC_UPD_FCPORT); fcport->login_retry = vha->hw->login_retry_count; fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT); + + spin_lock_irqsave(&vha->work_lock, flags); fcport->deleted = 0; + spin_unlock_irqrestore(&vha->work_lock, flags); + if (vha->hw->current_topology == ISP_CFG_NL) fcport->logout_on_delete = 0; else diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 5258b07687a94..2b815a9928ea3 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -1068,10 +1068,6 @@ void qlt_free_session_done(struct work_struct *work) (struct imm_ntfy_from_isp *)sess->iocb, SRB_NACK_LOGO); } - spin_lock_irqsave(&vha->work_lock, flags); - sess->flags &= ~FCF_ASYNC_SENT; - spin_unlock_irqrestore(&vha->work_lock, flags); - spin_lock_irqsave(&ha->tgt.sess_lock, flags); if (sess->se_sess) { sess->se_sess = NULL; @@ -1081,7 +1077,6 @@ void qlt_free_session_done(struct work_struct *work) qla2x00_set_fcport_disc_state(sess, DSC_DELETED); sess->fw_login_state = DSC_LS_PORT_UNAVAIL; - sess->deleted = QLA_SESS_DELETED; if (sess->login_succ && !IS_SW_RESV_ADDR(sess->d_id)) { vha->fcport_count--; @@ -1133,10 +1128,15 @@ void qlt_free_session_done(struct work_struct *work) sess->explicit_logout = 0; spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); - sess->free_pending = 0; qla2x00_dfs_remove_rport(vha, sess); + spin_lock_irqsave(&vha->work_lock, flags); + sess->flags &= ~FCF_ASYNC_SENT; + sess->deleted = QLA_SESS_DELETED; + sess->free_pending = 0; + spin_unlock_irqrestore(&vha->work_lock, flags); + ql_dbg(ql_dbg_disc, vha, 0xf001, "Unregistration of sess %p %8phC finished fcp_cnt %d\n", sess, sess->port_name, vha->fcport_count); @@ -1185,12 +1185,12 @@ void qlt_unreg_sess(struct fc_port *sess) * management from being sent. */ sess->flags |= FCF_ASYNC_SENT; + sess->deleted = QLA_SESS_DELETION_IN_PROGRESS; spin_unlock_irqrestore(&sess->vha->work_lock, flags); if (sess->se_sess) vha->hw->tgt.tgt_ops->clear_nacl_from_fcport_map(sess); - sess->deleted = QLA_SESS_DELETION_IN_PROGRESS; qla2x00_set_fcport_disc_state(sess, DSC_DELETE_PEND); sess->last_rscn_gen = sess->rscn_gen; sess->last_login_gen = sess->login_gen; -- GitLab From efa74a62aaa2429c04fe6cb277b3bf6739747d86 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 14 Jul 2023 12:30:56 +0530 Subject: [PATCH 0344/3445] scsi: qla2xxx: Adjust IOCB resource on qpair create During NVMe queue creation, a new qpair is created. FW resource limit needs to be re-adjusted to take into account the new qpair. Otherwise, NVMe command can not go through. This issue was discovered while testing/forcing FW execution to fail at load time. Add call to readjust IOCB and exchange limit. In addition, get FW state command and require FW to be running. Otherwise, error is generated. Cc: stable@vger.kernel.org Signed-off-by: Quinn Tran Signed-off-by: Nilesh Javali Link: https://lore.kernel.org/r/20230714070104.40052-3-njavali@marvell.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_gbl.h | 1 + drivers/scsi/qla2xxx/qla_init.c | 52 +++++++++++++++++++++------------ drivers/scsi/qla2xxx/qla_mbx.c | 3 ++ drivers/scsi/qla2xxx/qla_nvme.c | 1 + 4 files changed, 38 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index ba7831f24734f..33fba9d629693 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -143,6 +143,7 @@ void qla_edif_sess_down(struct scsi_qla_host *vha, struct fc_port *sess); void qla_edif_clear_appdata(struct scsi_qla_host *vha, struct fc_port *fcport); const char *sc_to_str(uint16_t cmd); +void qla_adjust_iocb_limit(scsi_qla_host_t *vha); /* * Global Data in qla_os.c source file. diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 5c2a646265e4c..eb25fc2451d3c 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -4153,41 +4153,55 @@ out: return ha->flags.lr_detected; } -void qla_init_iocb_limit(scsi_qla_host_t *vha) +static void __qla_adjust_iocb_limit(struct qla_qpair *qpair) { - u16 i, num_qps; - u32 limit; - struct qla_hw_data *ha = vha->hw; + u8 num_qps; + u16 limit; + struct qla_hw_data *ha = qpair->vha->hw; num_qps = ha->num_qpairs + 1; limit = (ha->orig_fw_iocb_count * QLA_IOCB_PCT_LIMIT) / 100; - ha->base_qpair->fwres.iocbs_total = ha->orig_fw_iocb_count; - ha->base_qpair->fwres.iocbs_limit = limit; - ha->base_qpair->fwres.iocbs_qp_limit = limit / num_qps; - ha->base_qpair->fwres.iocbs_used = 0; + qpair->fwres.iocbs_total = ha->orig_fw_iocb_count; + qpair->fwres.iocbs_limit = limit; + qpair->fwres.iocbs_qp_limit = limit / num_qps; + + qpair->fwres.exch_total = ha->orig_fw_xcb_count; + qpair->fwres.exch_limit = (ha->orig_fw_xcb_count * + QLA_IOCB_PCT_LIMIT) / 100; +} + +void qla_init_iocb_limit(scsi_qla_host_t *vha) +{ + u8 i; + struct qla_hw_data *ha = vha->hw; - ha->base_qpair->fwres.exch_total = ha->orig_fw_xcb_count; - ha->base_qpair->fwres.exch_limit = (ha->orig_fw_xcb_count * - QLA_IOCB_PCT_LIMIT) / 100; + __qla_adjust_iocb_limit(ha->base_qpair); + ha->base_qpair->fwres.iocbs_used = 0; ha->base_qpair->fwres.exch_used = 0; for (i = 0; i < ha->max_qpairs; i++) { if (ha->queue_pair_map[i]) { - ha->queue_pair_map[i]->fwres.iocbs_total = - ha->orig_fw_iocb_count; - ha->queue_pair_map[i]->fwres.iocbs_limit = limit; - ha->queue_pair_map[i]->fwres.iocbs_qp_limit = - limit / num_qps; + __qla_adjust_iocb_limit(ha->queue_pair_map[i]); ha->queue_pair_map[i]->fwres.iocbs_used = 0; - ha->queue_pair_map[i]->fwres.exch_total = ha->orig_fw_xcb_count; - ha->queue_pair_map[i]->fwres.exch_limit = - (ha->orig_fw_xcb_count * QLA_IOCB_PCT_LIMIT) / 100; ha->queue_pair_map[i]->fwres.exch_used = 0; } } } +void qla_adjust_iocb_limit(scsi_qla_host_t *vha) +{ + u8 i; + struct qla_hw_data *ha = vha->hw; + + __qla_adjust_iocb_limit(ha->base_qpair); + + for (i = 0; i < ha->max_qpairs; i++) { + if (ha->queue_pair_map[i]) + __qla_adjust_iocb_limit(ha->queue_pair_map[i]); + } +} + /** * qla2x00_setup_chip() - Load and start RISC firmware. * @vha: HA context diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 254fd4c642628..b05f930378756 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -2213,6 +2213,9 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states) ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1054, "Entered %s.\n", __func__); + if (!ha->flags.fw_started) + return QLA_FUNCTION_FAILED; + mcp->mb[0] = MBC_GET_FIRMWARE_STATE; mcp->out_mb = MBX_0; if (IS_FWI2_CAPABLE(vha->hw)) diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 86e85f2f4782f..6769c40287b9a 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -132,6 +132,7 @@ static int qla_nvme_alloc_queue(struct nvme_fc_local_port *lport, "Failed to allocate qpair\n"); return -EINVAL; } + qla_adjust_iocb_limit(vha); } *handle = qpair; -- GitLab From a8ec192427e0516436e61f9ca9eb49c54eadfe0a Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 14 Jul 2023 12:30:57 +0530 Subject: [PATCH 0345/3445] scsi: qla2xxx: Limit TMF to 8 per function Per FW recommendation, 8 TMF's can be outstanding for each function. Previously, it allowed 8 per target. Limit TMF to 8 per function. Cc: stable@vger.kernel.org Fixes: 6a87679626b5 ("scsi: qla2xxx: Fix task management cmd fail due to unavailable resource") Signed-off-by: Quinn Tran Signed-off-by: Nilesh Javali Link: https://lore.kernel.org/r/20230714070104.40052-4-njavali@marvell.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 9 +++--- drivers/scsi/qla2xxx/qla_init.c | 55 ++++++++++++++++++++------------- drivers/scsi/qla2xxx/qla_os.c | 2 ++ 3 files changed, 41 insertions(+), 25 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index d44c4d37b50b4..b3b1df34afd3a 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -466,6 +466,7 @@ static inline be_id_t port_id_to_be_id(port_id_t port_id) } struct tmf_arg { + struct list_head tmf_elem; struct qla_qpair *qpair; struct fc_port *fcport; struct scsi_qla_host *vha; @@ -2541,7 +2542,6 @@ enum rscn_addr_format { typedef struct fc_port { struct list_head list; struct scsi_qla_host *vha; - struct list_head tmf_pending; unsigned int conf_compl_supported:1; unsigned int deleted:2; @@ -2562,9 +2562,6 @@ typedef struct fc_port { unsigned int do_prli_nvme:1; uint8_t nvme_flag; - uint8_t active_tmf; -#define MAX_ACTIVE_TMF 8 - uint8_t node_name[WWN_SIZE]; uint8_t port_name[WWN_SIZE]; port_id_t d_id; @@ -4657,6 +4654,8 @@ struct qla_hw_data { uint32_t flt_region_aux_img_status_sec; }; uint8_t active_image; + uint8_t active_tmf; +#define MAX_ACTIVE_TMF 8 /* Needed for BEACON */ uint16_t beacon_blink_led; @@ -4671,6 +4670,8 @@ struct qla_hw_data { struct qla_msix_entry *msix_entries; + struct list_head tmf_pending; + struct list_head tmf_active; struct list_head vp_list; /* list of VP */ unsigned long vp_idx_map[(MAX_MULTI_ID_FABRIC / 8) / sizeof(unsigned long)]; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index eb25fc2451d3c..404b32ceeaa2b 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -2192,30 +2192,42 @@ done: return rval; } -static void qla_put_tmf(fc_port_t *fcport) +static void qla_put_tmf(struct tmf_arg *arg) { - struct scsi_qla_host *vha = fcport->vha; + struct scsi_qla_host *vha = arg->vha; struct qla_hw_data *ha = vha->hw; unsigned long flags; spin_lock_irqsave(&ha->tgt.sess_lock, flags); - fcport->active_tmf--; + ha->active_tmf--; + list_del(&arg->tmf_elem); spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); } static -int qla_get_tmf(fc_port_t *fcport) +int qla_get_tmf(struct tmf_arg *arg) { - struct scsi_qla_host *vha = fcport->vha; + struct scsi_qla_host *vha = arg->vha; struct qla_hw_data *ha = vha->hw; unsigned long flags; + fc_port_t *fcport = arg->fcport; int rc = 0; - LIST_HEAD(tmf_elem); + struct tmf_arg *t; spin_lock_irqsave(&ha->tgt.sess_lock, flags); - list_add_tail(&tmf_elem, &fcport->tmf_pending); + list_for_each_entry(t, &ha->tmf_active, tmf_elem) { + if (t->fcport == arg->fcport && t->lun == arg->lun) { + /* reject duplicate TMF */ + ql_log(ql_log_warn, vha, 0x802c, + "found duplicate TMF. Nexus=%ld:%06x:%llu.\n", + vha->host_no, fcport->d_id.b24, arg->lun); + spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); + return -EINVAL; + } + } - while (fcport->active_tmf >= MAX_ACTIVE_TMF) { + list_add_tail(&arg->tmf_elem, &ha->tmf_pending); + while (ha->active_tmf >= MAX_ACTIVE_TMF) { spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); msleep(1); @@ -2227,15 +2239,17 @@ int qla_get_tmf(fc_port_t *fcport) rc = EIO; break; } - if (fcport->active_tmf < MAX_ACTIVE_TMF && - list_is_first(&tmf_elem, &fcport->tmf_pending)) + if (ha->active_tmf < MAX_ACTIVE_TMF && + list_is_first(&arg->tmf_elem, &ha->tmf_pending)) break; } - list_del(&tmf_elem); + list_del(&arg->tmf_elem); - if (!rc) - fcport->active_tmf++; + if (!rc) { + ha->active_tmf++; + list_add_tail(&arg->tmf_elem, &ha->tmf_active); + } spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); @@ -2257,15 +2271,18 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun, a.vha = fcport->vha; a.fcport = fcport; a.lun = lun; + a.flags = flags; + INIT_LIST_HEAD(&a.tmf_elem); + if (flags & (TCF_LUN_RESET|TCF_ABORT_TASK_SET|TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA)) { a.modifier = MK_SYNC_ID_LUN; - - if (qla_get_tmf(fcport)) - return QLA_FUNCTION_FAILED; } else { a.modifier = MK_SYNC_ID; } + if (qla_get_tmf(&a)) + return QLA_FUNCTION_FAILED; + if (vha->hw->mqenable) { for (i = 0; i < vha->hw->num_qpairs; i++) { qpair = vha->hw->queue_pair_map[i]; @@ -2291,13 +2308,10 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun, goto bailout; a.qpair = vha->hw->base_qpair; - a.flags = flags; rval = __qla2x00_async_tm_cmd(&a); bailout: - if (a.modifier == MK_SYNC_ID_LUN) - qla_put_tmf(fcport); - + qla_put_tmf(&a); return rval; } @@ -5526,7 +5540,6 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags) INIT_WORK(&fcport->reg_work, qla_register_fcport_fn); INIT_LIST_HEAD(&fcport->gnl_entry); INIT_LIST_HEAD(&fcport->list); - INIT_LIST_HEAD(&fcport->tmf_pending); INIT_LIST_HEAD(&fcport->sess_cmd_list); spin_lock_init(&fcport->sess_cmd_lock); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 877e4f446709d..47bbc8b321f8b 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3009,6 +3009,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) atomic_set(&ha->num_pend_mbx_stage3, 0); atomic_set(&ha->zio_threshold, DEFAULT_ZIO_THRESHOLD); ha->last_zio_threshold = DEFAULT_ZIO_THRESHOLD; + INIT_LIST_HEAD(&ha->tmf_pending); + INIT_LIST_HEAD(&ha->tmf_active); /* Assign ISP specific operations. */ if (IS_QLA2100(ha)) { -- GitLab From da7c21b72aa86e990af5f73bce6590b8d8d148d0 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 14 Jul 2023 12:30:58 +0530 Subject: [PATCH 0346/3445] scsi: qla2xxx: Fix command flush during TMF For each TMF request, driver iterates through each qpair and flushes commands associated to the TMF. At the end of the qpair flush, a Marker is used to complete the flush transaction. This process was repeated for each qpair. The multiple flush and marker for this TMF request seems to cause confusion for FW. Instead, 1 flush is sent to FW. Driver would wait for FW to go through all the I/Os on each qpair to be read then return. Driver then closes out the transaction with a Marker. Cc: stable@vger.kernel.org Fixes: d90171dd0da5 ("scsi: qla2xxx: Multi-que support for TMF") Signed-off-by: Quinn Tran Signed-off-by: Nilesh Javali Link: https://lore.kernel.org/r/20230714070104.40052-5-njavali@marvell.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 74 +++++++++++++++++---------------- drivers/scsi/qla2xxx/qla_iocb.c | 1 + drivers/scsi/qla2xxx/qla_os.c | 9 ++-- 3 files changed, 45 insertions(+), 39 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 404b32ceeaa2b..f6f172fa1e184 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -2002,12 +2002,11 @@ qla2x00_tmf_iocb_timeout(void *data) int rc, h; unsigned long flags; - if (sp->type == SRB_MARKER) { - complete(&tmf->u.tmf.comp); - return; - } + if (sp->type == SRB_MARKER) + rc = QLA_FUNCTION_FAILED; + else + rc = qla24xx_async_abort_cmd(sp, false); - rc = qla24xx_async_abort_cmd(sp, false); if (rc) { spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags); for (h = 1; h < sp->qpair->req->num_outstanding_cmds; h++) { @@ -2129,6 +2128,17 @@ static void qla2x00_tmf_sp_done(srb_t *sp, int res) complete(&tmf->u.tmf.comp); } +static int qla_tmf_wait(struct tmf_arg *arg) +{ + /* there are only 2 types of error handling that reaches here, lun or target reset */ + if (arg->flags & (TCF_LUN_RESET | TCF_ABORT_TASK_SET | TCF_CLEAR_TASK_SET)) + return qla2x00_eh_wait_for_pending_commands(arg->vha, + arg->fcport->d_id.b24, arg->lun, WAIT_LUN); + else + return qla2x00_eh_wait_for_pending_commands(arg->vha, + arg->fcport->d_id.b24, arg->lun, WAIT_TARGET); +} + static int __qla2x00_async_tm_cmd(struct tmf_arg *arg) { @@ -2136,8 +2146,9 @@ __qla2x00_async_tm_cmd(struct tmf_arg *arg) struct srb_iocb *tm_iocb; srb_t *sp; int rval = QLA_FUNCTION_FAILED; - fc_port_t *fcport = arg->fcport; + u32 chip_gen, login_gen; + u64 jif; if (TMF_NOT_READY(arg->fcport)) { ql_dbg(ql_dbg_taskm, vha, 0x8032, @@ -2182,8 +2193,27 @@ __qla2x00_async_tm_cmd(struct tmf_arg *arg) "TM IOCB failed (%x).\n", rval); } - if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw)) - rval = qla26xx_marker(arg); + if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw)) { + chip_gen = vha->hw->chip_reset; + login_gen = fcport->login_gen; + + jif = jiffies; + if (qla_tmf_wait(arg)) { + ql_log(ql_log_info, vha, 0x803e, + "Waited %u ms Nexus=%ld:%06x:%llu.\n", + jiffies_to_msecs(jiffies - jif), vha->host_no, + fcport->d_id.b24, arg->lun); + } + + if (chip_gen == vha->hw->chip_reset && login_gen == fcport->login_gen) { + rval = qla26xx_marker(arg); + } else { + ql_log(ql_log_info, vha, 0x803e, + "Skip Marker due to disruption. Nexus=%ld:%06x:%llu.\n", + vha->host_no, fcport->d_id.b24, arg->lun); + rval = QLA_FUNCTION_FAILED; + } + } done_free_sp: /* ref: INIT */ @@ -2261,9 +2291,8 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun, uint32_t tag) { struct scsi_qla_host *vha = fcport->vha; - struct qla_qpair *qpair; struct tmf_arg a; - int i, rval = QLA_SUCCESS; + int rval = QLA_SUCCESS; if (TMF_NOT_READY(fcport)) return QLA_SUSPENDED; @@ -2283,34 +2312,9 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun, if (qla_get_tmf(&a)) return QLA_FUNCTION_FAILED; - if (vha->hw->mqenable) { - for (i = 0; i < vha->hw->num_qpairs; i++) { - qpair = vha->hw->queue_pair_map[i]; - if (!qpair) - continue; - - if (TMF_NOT_READY(fcport)) { - ql_log(ql_log_warn, vha, 0x8026, - "Unable to send TM due to disruption.\n"); - rval = QLA_SUSPENDED; - break; - } - - a.qpair = qpair; - a.flags = flags|TCF_NOTMCMD_TO_TARGET; - rval = __qla2x00_async_tm_cmd(&a); - if (rval) - break; - } - } - - if (rval) - goto bailout; - a.qpair = vha->hw->base_qpair; rval = __qla2x00_async_tm_cmd(&a); -bailout: qla_put_tmf(&a); return rval; } diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index a1675f056a5c2..1c6e300ed3abb 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -3881,6 +3881,7 @@ qla_marker_iocb(srb_t *sp, struct mrk_entry_24xx *mrk) { mrk->entry_type = MARKER_TYPE; mrk->modifier = sp->u.iocb_cmd.u.tmf.modifier; + mrk->handle = make_handle(sp->qpair->req->id, sp->handle); if (sp->u.iocb_cmd.u.tmf.modifier != MK_SYNC_ALL) { mrk->nport_handle = cpu_to_le16(sp->u.iocb_cmd.u.tmf.loop_id); int_to_scsilun(sp->u.iocb_cmd.u.tmf.lun, (struct scsi_lun *)&mrk->lun); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 47bbc8b321f8b..03bc3a0b45b6f 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1488,8 +1488,9 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) goto eh_reset_failed; } err = 3; - if (qla2x00_eh_wait_for_pending_commands(vha, sdev->id, - sdev->lun, WAIT_LUN) != QLA_SUCCESS) { + if (qla2x00_eh_wait_for_pending_commands(vha, fcport->d_id.b24, + cmd->device->lun, + WAIT_LUN) != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x800d, "wait for pending cmds failed for cmd=%p.\n", cmd); goto eh_reset_failed; @@ -1555,8 +1556,8 @@ qla2xxx_eh_target_reset(struct scsi_cmnd *cmd) goto eh_reset_failed; } err = 3; - if (qla2x00_eh_wait_for_pending_commands(vha, sdev->id, - 0, WAIT_TARGET) != QLA_SUCCESS) { + if (qla2x00_eh_wait_for_pending_commands(vha, fcport->d_id.b24, 0, + WAIT_TARGET) != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x800d, "wait for pending cmds failed for cmd=%p.\n", cmd); goto eh_reset_failed; -- GitLab From 5b51f35d127e7bef55fa869d2465e2bca4636454 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 14 Jul 2023 12:30:59 +0530 Subject: [PATCH 0347/3445] scsi: qla2xxx: Fix erroneous link up failure Link up failure occurred where driver failed to see certain events from FW indicating link up (AEN 8011) and fabric login completion (AEN 8014). Without these 2 events, driver would not proceed forward to scan the fabric. The cause of this is due to delay in the receive of interrupt for Mailbox 60 that causes qla to set the fw_started flag late. The late setting of this flag causes other interrupts to be dropped. These dropped interrupts happen to be the link up (AEN 8011) and fabric login completion (AEN 8014). Set fw_started flag early to prevent interrupts being dropped. Cc: stable@vger.kernel.org Signed-off-by: Quinn Tran Signed-off-by: Nilesh Javali Link: https://lore.kernel.org/r/20230714070104.40052-6-njavali@marvell.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 3 ++- drivers/scsi/qla2xxx/qla_isr.c | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index f6f172fa1e184..1236acb1fd833 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -4815,15 +4815,16 @@ qla2x00_init_rings(scsi_qla_host_t *vha) if (ha->flags.edif_enabled) mid_init_cb->init_cb.frame_payload_size = cpu_to_le16(ELS_MAX_PAYLOAD); + QLA_FW_STARTED(ha); rval = qla2x00_init_firmware(vha, ha->init_cb_size); next_check: if (rval) { + QLA_FW_STOPPED(ha); ql_log(ql_log_fatal, vha, 0x00d2, "Init Firmware **** FAILED ****.\n"); } else { ql_dbg(ql_dbg_init, vha, 0x00d3, "Init Firmware -- success.\n"); - QLA_FW_STARTED(ha); vha->u_ql2xexchoffld = vha->u_ql2xiniexchg = 0; } diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 656700f793259..c1b6fce9c415f 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1121,8 +1121,12 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) unsigned long flags; fc_port_t *fcport = NULL; - if (!vha->hw->flags.fw_started) + if (!vha->hw->flags.fw_started) { + ql_log(ql_log_warn, vha, 0x50ff, + "Dropping AEN - %04x %04x %04x %04x.\n", + mb[0], mb[1], mb[2], mb[3]); return; + } /* Setup to process RIO completion. */ handle_cnt = 0; -- GitLab From 39d22740712c7563a2e18c08f033deeacdaf66e7 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 14 Jul 2023 12:31:00 +0530 Subject: [PATCH 0348/3445] scsi: qla2xxx: Fix session hang in gnl Connection does not resume after a host reset / chip reset. The cause of the blockage is due to the FCF_ASYNC_ACTIVE left on. The gnl command was interrupted by the chip reset. On exiting the command, this flag should be turn off to allow relogin to reoccur. Clear this flag to prevent blockage. Cc: stable@vger.kernel.org Fixes: 17e64648aa47 ("scsi: qla2xxx: Correct fcport flags handling") Signed-off-by: Quinn Tran Signed-off-by: Nilesh Javali Link: https://lore.kernel.org/r/20230714070104.40052-7-njavali@marvell.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 1236acb1fd833..7ac4738fda254 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1141,7 +1141,7 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport) u16 *mb; if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT)) - return rval; + goto done; ql_dbg(ql_dbg_disc, vha, 0x20d9, "Async-gnlist WWPN %8phC \n", fcport->port_name); @@ -1195,8 +1195,9 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport) done_free_sp: /* ref: INIT */ kref_put(&sp->cmd_kref, qla2x00_sp_release); + fcport->flags &= ~(FCF_ASYNC_SENT); done: - fcport->flags &= ~(FCF_ASYNC_ACTIVE | FCF_ASYNC_SENT); + fcport->flags &= ~(FCF_ASYNC_ACTIVE); return rval; } -- GitLab From 8ebaa45163a3fedc885c1dc7d43ea987a2f00a06 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 14 Jul 2023 12:31:01 +0530 Subject: [PATCH 0349/3445] scsi: qla2xxx: Turn off noisy message log Some consider noisy log as test failure. Turn off noisy message log. Cc: stable@vger.kernel.org Signed-off-by: Quinn Tran Signed-off-by: Nilesh Javali Link: https://lore.kernel.org/r/20230714070104.40052-8-njavali@marvell.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_nvme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 6769c40287b9a..9941b38eac93c 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -668,7 +668,7 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport, rval = qla2x00_start_nvme_mq(sp); if (rval != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x212d, + ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x212d, "qla2x00_start_nvme_mq failed = %d\n", rval); sp->priv = NULL; priv->sp = NULL; -- GitLab From 5d3148d8e8b05f084e607ac3bd55a4c317a9f934 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 14 Jul 2023 12:31:02 +0530 Subject: [PATCH 0350/3445] scsi: qla2xxx: Fix TMF leak through Task management can retry up to 5 times when FW resource becomes bottle neck. Between the retries, there is a short sleep. Current code assumes the chip has not reset or session has not changed. Check for chip reset or session change before sending Task management. Cc: stable@vger.kernel.org Fixes: 9803fb5d2759 ("scsi: qla2xxx: Fix task management cmd failure") Signed-off-by: Quinn Tran Signed-off-by: Nilesh Javali Link: https://lore.kernel.org/r/20230714070104.40052-9-njavali@marvell.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 7ac4738fda254..059175f2c8f52 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -2038,10 +2038,14 @@ static void qla_marker_sp_done(srb_t *sp, int res) complete(&tmf->u.tmf.comp); } -#define START_SP_W_RETRIES(_sp, _rval) \ +#define START_SP_W_RETRIES(_sp, _rval, _chip_gen, _login_gen) \ {\ int cnt = 5; \ do { \ + if (_chip_gen != sp->vha->hw->chip_reset || _login_gen != sp->fcport->login_gen) {\ + _rval = EINVAL; \ + break; \ + } \ _rval = qla2x00_start_sp(_sp); \ if (_rval == EAGAIN) \ msleep(1); \ @@ -2064,6 +2068,7 @@ qla26xx_marker(struct tmf_arg *arg) srb_t *sp; int rval = QLA_FUNCTION_FAILED; fc_port_t *fcport = arg->fcport; + u32 chip_gen, login_gen; if (TMF_NOT_READY(arg->fcport)) { ql_dbg(ql_dbg_taskm, vha, 0x8039, @@ -2073,6 +2078,9 @@ qla26xx_marker(struct tmf_arg *arg) return QLA_SUSPENDED; } + chip_gen = vha->hw->chip_reset; + login_gen = fcport->login_gen; + /* ref: INIT */ sp = qla2xxx_get_qpair_sp(vha, arg->qpair, fcport, GFP_KERNEL); if (!sp) @@ -2090,7 +2098,7 @@ qla26xx_marker(struct tmf_arg *arg) tm_iocb->u.tmf.loop_id = fcport->loop_id; tm_iocb->u.tmf.vp_index = vha->vp_idx; - START_SP_W_RETRIES(sp, rval); + START_SP_W_RETRIES(sp, rval, chip_gen, login_gen); ql_dbg(ql_dbg_taskm, vha, 0x8006, "Async-marker hdl=%x loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d rval %d.\n", @@ -2159,6 +2167,9 @@ __qla2x00_async_tm_cmd(struct tmf_arg *arg) return QLA_SUSPENDED; } + chip_gen = vha->hw->chip_reset; + login_gen = fcport->login_gen; + /* ref: INIT */ sp = qla2xxx_get_qpair_sp(vha, arg->qpair, fcport, GFP_KERNEL); if (!sp) @@ -2176,7 +2187,7 @@ __qla2x00_async_tm_cmd(struct tmf_arg *arg) tm_iocb->u.tmf.flags = arg->flags; tm_iocb->u.tmf.lun = arg->lun; - START_SP_W_RETRIES(sp, rval); + START_SP_W_RETRIES(sp, rval, chip_gen, login_gen); ql_dbg(ql_dbg_taskm, vha, 0x802f, "Async-tmf hdl=%x loop-id=%x portid=%06x ctrl=%x lun=%lld qp=%d rval=%x.\n", @@ -2195,9 +2206,6 @@ __qla2x00_async_tm_cmd(struct tmf_arg *arg) } if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw)) { - chip_gen = vha->hw->chip_reset; - login_gen = fcport->login_gen; - jif = jiffies; if (qla_tmf_wait(arg)) { ql_log(ql_log_info, vha, 0x803e, -- GitLab From 009e7fe4a1ed52276b332842a6b6e23b07200f2d Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Fri, 14 Jul 2023 12:31:03 +0530 Subject: [PATCH 0351/3445] scsi: qla2xxx: fix inconsistent TMF timeout Different behavior were experienced of session being torn down vs not when TMF is timed out. When FW detects the time out, the session is torn down. When driver detects the time out, the session is not torn down. Allow TMF error to return to upper layer without session tear down. Cc: stable@vger.kernel.org Signed-off-by: Quinn Tran Signed-off-by: Nilesh Javali Link: https://lore.kernel.org/r/20230714070104.40052-10-njavali@marvell.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_isr.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index c1b6fce9c415f..1f42a413b5988 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2543,7 +2543,6 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk) case CS_PORT_BUSY: case CS_INCOMPLETE: case CS_PORT_UNAVAILABLE: - case CS_TIMEOUT: case CS_RESET: if (atomic_read(&fcport->state) == FCS_ONLINE) { ql_dbg(ql_dbg_disc, fcport->vha, 0x3021, -- GitLab From a31a596a426555ff603599e115466d596a1abd85 Mon Sep 17 00:00:00 2001 From: Nilesh Javali Date: Fri, 14 Jul 2023 12:31:04 +0530 Subject: [PATCH 0352/3445] scsi: qla2xxx: Update version to 10.02.08.500-k Signed-off-by: Nilesh Javali Link: https://lore.kernel.org/r/20230714070104.40052-11-njavali@marvell.com Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index e3771923b0d7d..81bdf6b032418 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -6,9 +6,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "10.02.08.400-k" +#define QLA2XXX_VERSION "10.02.08.500-k" #define QLA_DRIVER_MAJOR_VER 10 #define QLA_DRIVER_MINOR_VER 2 #define QLA_DRIVER_PATCH_VER 8 -#define QLA_DRIVER_BETA_VER 400 +#define QLA_DRIVER_BETA_VER 500 -- GitLab From 0645ab15ed0bf5b17ad510bd72ef589cda542795 Mon Sep 17 00:00:00 2001 From: Nitin Rawat Date: Thu, 20 Jul 2023 15:04:46 +0530 Subject: [PATCH 0353/3445] scsi: ufs: ufs-qcom: Change UFS devfreq timer to delayed Devfreq uses the default DEVFREQ_TIMER_DEFERRABLE mode which uses the deferred timer for scheduling the devfreq load monitor function. This causes the load monitoring to be done only with non-idle CPUs and not making use of the idle CPUs. Hence, use the DEVFREQ_TIMER_DELAYED mode which uses the delayed timer thereby making use of idle CPUs as well for load monitoring. Co-developed-by: Asutosh Das Signed-off-by: Asutosh Das Signed-off-by: Nitin Rawat Link: https://lore.kernel.org/r/20230720093446.30697-1-quic_nitirawa@quicinc.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index d29e63e4a4f8f..3ee5ff905f9a6 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1483,6 +1483,7 @@ static void ufs_qcom_config_scaling_param(struct ufs_hba *hba, struct devfreq_simple_ondemand_data *d) { p->polling_ms = 60; + p->timer = DEVFREQ_TIMER_DELAYED; d->upthreshold = 70; d->downdifferential = 5; } -- GitLab From f669b8a683e4ee26fa5cafe19d71cec1786b556a Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 21 Jul 2023 09:01:32 -0700 Subject: [PATCH 0354/3445] scsi: core: Fix the scsi_set_resid() documentation Because scsi_finish_command() subtracts the residual from the buffer length, residual overflows must not be reported. Reflect this in the SCSI documentation. See also commit 9237f04e12cc ("scsi: core: Fix scsi_get/set_resid() interface") Cc: Damien Le Moal Cc: Hannes Reinecke Cc: Douglas Gilbert Cc: stable@vger.kernel.org Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20230721160154.874010-2-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- Documentation/scsi/scsi_mid_low_api.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/scsi/scsi_mid_low_api.rst b/Documentation/scsi/scsi_mid_low_api.rst index 6fa3a62795016..022198c513506 100644 --- a/Documentation/scsi/scsi_mid_low_api.rst +++ b/Documentation/scsi/scsi_mid_low_api.rst @@ -1190,11 +1190,11 @@ Members of interest: - pointer to scsi_device object that this command is associated with. resid - - an LLD should set this signed integer to the requested + - an LLD should set this unsigned integer to the requested transfer length (i.e. 'request_bufflen') less the number of bytes that are actually transferred. 'resid' is preset to 0 so an LLD can ignore it if it cannot detect - underruns (overruns should be rare). If possible an LLD + underruns (overruns should not be reported). An LLD should set 'resid' prior to invoking 'done'. The most interesting case is data transfers from a SCSI target device (e.g. READs) that underrun. -- GitLab From 7e9609d2daea0ebe4add444b26b76479ecfda504 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 19 Jul 2023 09:55:41 -0700 Subject: [PATCH 0355/3445] scsi: ufs: core: Remove HPB support Interest among UFS users in HPB has reduced significantly. I am not aware of any current users of the HPB functionality. Hence remove HPB support from the kernel. A note: the work in JEDEC on a successor for HPB is nearing completion. Zoned storage for UFS or ZUFS combines the UFS standard with ZBC-2. Acked-by: Avri Altman Reviewed-by: Bean Huo Cc: Adrian Hunter Cc: ChanWoo Lee Cc: Daejun Park Cc: Keoseong Park Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20230719165758.2787573-1-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- Documentation/ABI/testing/sysfs-driver-ufs | 247 -- drivers/ufs/core/Kconfig | 8 - drivers/ufs/core/Makefile | 1 - drivers/ufs/core/ufs-sysfs.c | 22 - drivers/ufs/core/ufshcd.c | 67 +- drivers/ufs/core/ufshpb.c | 2668 -------------------- drivers/ufs/core/ufshpb.h | 318 --- include/ufs/ufs.h | 39 - include/ufs/ufs_quirks.h | 6 - include/ufs/ufshcd.h | 30 - 10 files changed, 1 insertion(+), 3405 deletions(-) delete mode 100644 drivers/ufs/core/ufshpb.c delete mode 100644 drivers/ufs/core/ufshpb.h diff --git a/Documentation/ABI/testing/sysfs-driver-ufs b/Documentation/ABI/testing/sysfs-driver-ufs index d5f44fc5b9dca..106687f4f6b77 100644 --- a/Documentation/ABI/testing/sysfs-driver-ufs +++ b/Documentation/ABI/testing/sysfs-driver-ufs @@ -1437,180 +1437,6 @@ Description: If avail_wb_buff < wb_flush_threshold, it indicates that WriteBooster buffer needs to be flushed, otherwise it is not necessary. -What: /sys/bus/platform/drivers/ufshcd/*/device_descriptor/hpb_version -What: /sys/bus/platform/devices/*.ufs/device_descriptor/hpb_version -Date: June 2021 -Contact: Daejun Park -Description: This entry shows the HPB specification version. - The full information about the descriptor can be found in the UFS - HPB (Host Performance Booster) Extension specifications. - Example: version 1.2.3 = 0123h - - The file is read only. - -What: /sys/bus/platform/drivers/ufshcd/*/device_descriptor/hpb_control -What: /sys/bus/platform/devices/*.ufs/device_descriptor/hpb_control -Date: June 2021 -Contact: Daejun Park -Description: This entry shows an indication of the HPB control mode. - 00h: Host control mode - 01h: Device control mode - - The file is read only. - -What: /sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/hpb_region_size -What: /sys/bus/platform/devices/*.ufs/geometry_descriptor/hpb_region_size -Date: June 2021 -Contact: Daejun Park -Description: This entry shows the bHPBRegionSize which can be calculated - as in the following (in bytes): - HPB Region size = 512B * 2^bHPBRegionSize - - The file is read only. - -What: /sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/hpb_number_lu -What: /sys/bus/platform/devices/*.ufs/geometry_descriptor/hpb_number_lu -Date: June 2021 -Contact: Daejun Park -Description: This entry shows the maximum number of HPB LU supported by - the device. - 00h: HPB is not supported by the device. - 01h ~ 20h: Maximum number of HPB LU supported by the device - - The file is read only. - -What: /sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/hpb_subregion_size -What: /sys/bus/platform/devices/*.ufs/geometry_descriptor/hpb_subregion_size -Date: June 2021 -Contact: Daejun Park -Description: This entry shows the bHPBSubRegionSize, which can be - calculated as in the following (in bytes) and shall be a multiple of - logical block size: - HPB Sub-Region size = 512B x 2^bHPBSubRegionSize - bHPBSubRegionSize shall not exceed bHPBRegionSize. - - The file is read only. - -What: /sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/hpb_max_active_regions -What: /sys/bus/platform/devices/*.ufs/geometry_descriptor/hpb_max_active_regions -Date: June 2021 -Contact: Daejun Park -Description: This entry shows the maximum number of active HPB regions that - is supported by the device. - - The file is read only. - -What: /sys/class/scsi_device/*/device/unit_descriptor/hpb_lu_max_active_regions -Date: June 2021 -Contact: Daejun Park -Description: This entry shows the maximum number of HPB regions assigned to - the HPB logical unit. - - The file is read only. - -What: /sys/class/scsi_device/*/device/unit_descriptor/hpb_pinned_region_start_offset -Date: June 2021 -Contact: Daejun Park -Description: This entry shows the start offset of HPB pinned region. - - The file is read only. - -What: /sys/class/scsi_device/*/device/unit_descriptor/hpb_number_pinned_regions -Date: June 2021 -Contact: Daejun Park -Description: This entry shows the number of HPB pinned regions assigned to - the HPB logical unit. - - The file is read only. - -What: /sys/class/scsi_device/*/device/hpb_stats/hit_cnt -Date: June 2021 -Contact: Daejun Park -Description: This entry shows the number of reads that changed to HPB read. - - The file is read only. - -What: /sys/class/scsi_device/*/device/hpb_stats/miss_cnt -Date: June 2021 -Contact: Daejun Park -Description: This entry shows the number of reads that cannot be changed to - HPB read. - - The file is read only. - -What: /sys/class/scsi_device/*/device/hpb_stats/rcmd_noti_cnt -Date: June 2021 -Contact: Daejun Park -Description: This entry shows the number of response UPIUs that has - recommendations for activating sub-regions and/or inactivating region. - - The file is read only. - -What: /sys/class/scsi_device/*/device/hpb_stats/rcmd_active_cnt -Date: June 2021 -Contact: Daejun Park -Description: For the HPB device control mode, this entry shows the number of - active sub-regions recommended by response UPIUs. For the HPB host control - mode, this entry shows the number of active sub-regions recommended by the - HPB host control mode heuristic algorithm. - - The file is read only. - -What: /sys/class/scsi_device/*/device/hpb_stats/rcmd_inactive_cnt -Date: June 2021 -Contact: Daejun Park -Description: For the HPB device control mode, this entry shows the number of - inactive regions recommended by response UPIUs. For the HPB host control - mode, this entry shows the number of inactive regions recommended by the - HPB host control mode heuristic algorithm. - - The file is read only. - -What: /sys/class/scsi_device/*/device/hpb_stats/map_req_cnt -Date: June 2021 -Contact: Daejun Park -Description: This entry shows the number of read buffer commands for - activating sub-regions recommended by response UPIUs. - - The file is read only. - -What: /sys/class/scsi_device/*/device/hpb_params/requeue_timeout_ms -Date: June 2021 -Contact: Daejun Park -Description: This entry shows the requeue timeout threshold for write buffer - command in ms. The value can be changed by writing an integer to - this entry. - -What: /sys/bus/platform/drivers/ufshcd/*/attributes/max_data_size_hpb_single_cmd -What: /sys/bus/platform/devices/*.ufs/attributes/max_data_size_hpb_single_cmd -Date: June 2021 -Contact: Daejun Park -Description: This entry shows the maximum HPB data size for using a single HPB - command. - - === ======== - 00h 4KB - 01h 8KB - 02h 12KB - ... - FFh 1024KB - === ======== - - The file is read only. - -What: /sys/bus/platform/drivers/ufshcd/*/flags/hpb_enable -What: /sys/bus/platform/devices/*.ufs/flags/hpb_enable -Date: June 2021 -Contact: Daejun Park -Description: This entry shows the status of HPB. - - == ============================ - 0 HPB is not enabled. - 1 HPB is enabled - == ============================ - - The file is read only. - Contact: Daniil Lunev What: /sys/bus/platform/drivers/ufshcd/*/capabilities/ What: /sys/bus/platform/devices/*.ufs/capabilities/ @@ -1648,76 +1474,3 @@ Description: Indicates status of Write Booster. The file is read only. -What: /sys/class/scsi_device/*/device/hpb_param_sysfs/activation_thld -Date: February 2021 -Contact: Avri Altman -Description: In host control mode, reads are the major source of activation - trials. Once this threshold hs met, the region is added to the - "to-be-activated" list. Since we reset the read counter upon - write, this include sending a rb command updating the region - ppn as well. - -What: /sys/class/scsi_device/*/device/hpb_param_sysfs/normalization_factor -Date: February 2021 -Contact: Avri Altman -Description: In host control mode, we think of the regions as "buckets". - Those buckets are being filled with reads, and emptied on write. - We use entries_per_srgn - the amount of blocks in a subregion as - our bucket size. This applies because HPB1.0 only handles - single-block reads. Once the bucket size is crossed, we trigger - a normalization work - not only to avoid overflow, but mainly - because we want to keep those counters normalized, as we are - using those reads as a comparative score, to make various decisions. - The normalization is dividing (shift right) the read counter by - the normalization_factor. If during consecutive normalizations - an active region has exhausted its reads - inactivate it. - -What: /sys/class/scsi_device/*/device/hpb_param_sysfs/eviction_thld_enter -Date: February 2021 -Contact: Avri Altman -Description: Region deactivation is often due to the fact that eviction took - place: A region becomes active at the expense of another. This is - happening when the max-active-regions limit has been crossed. - In host mode, eviction is considered an extreme measure. We - want to verify that the entering region has enough reads, and - the exiting region has much fewer reads. eviction_thld_enter is - the min reads that a region must have in order to be considered - a candidate for evicting another region. - -What: /sys/class/scsi_device/*/device/hpb_param_sysfs/eviction_thld_exit -Date: February 2021 -Contact: Avri Altman -Description: Same as above for the exiting region. A region is considered to - be a candidate for eviction only if it has fewer reads than - eviction_thld_exit. - -What: /sys/class/scsi_device/*/device/hpb_param_sysfs/read_timeout_ms -Date: February 2021 -Contact: Avri Altman -Description: In order not to hang on to "cold" regions, we inactivate - a region that has no READ access for a predefined amount of - time - read_timeout_ms. If read_timeout_ms has expired, and the - region is dirty, it is less likely that we can make any use of - HPB reading it so we inactivate it. Still, deactivation has - its overhead, and we may still benefit from HPB reading this - region if it is clean - see read_timeout_expiries. - -What: /sys/class/scsi_device/*/device/hpb_param_sysfs/read_timeout_expiries -Date: February 2021 -Contact: Avri Altman -Description: If the region read timeout has expired, but the region is clean, - just re-wind its timer for another spin. Do that as long as it - is clean and did not exhaust its read_timeout_expiries threshold. - -What: /sys/class/scsi_device/*/device/hpb_param_sysfs/timeout_polling_interval_ms -Date: February 2021 -Contact: Avri Altman -Description: The frequency with which the delayed worker that checks the - read_timeouts is awakened. - -What: /sys/class/scsi_device/*/device/hpb_param_sysfs/inflight_map_req -Date: February 2021 -Contact: Avri Altman -Description: In host control mode the host is the originator of map requests. - To avoid flooding the device with map requests, use a simple throttling - mechanism that limits the number of inflight map requests. diff --git a/drivers/ufs/core/Kconfig b/drivers/ufs/core/Kconfig index e11978171403a..817208ee64ecf 100644 --- a/drivers/ufs/core/Kconfig +++ b/drivers/ufs/core/Kconfig @@ -35,14 +35,6 @@ config SCSI_UFS_CRYPTO capabilities of the UFS device (if present) to perform crypto operations on data being transferred to/from the device. -config SCSI_UFS_HPB - bool "Support UFS Host Performance Booster" - help - The UFS HPB feature improves random read performance. It caches - L2P (logical to physical) map of UFS to host DRAM. The driver uses HPB - read command by piggybacking physical page number for bypassing FTL (flash - translation layer)'s L2P address translation. - config SCSI_UFS_FAULT_INJECTION bool "UFS Fault Injection Support" depends on FAULT_INJECTION diff --git a/drivers/ufs/core/Makefile b/drivers/ufs/core/Makefile index 4d02e0f2de10a..cf820fa09a048 100644 --- a/drivers/ufs/core/Makefile +++ b/drivers/ufs/core/Makefile @@ -5,6 +5,5 @@ ufshcd-core-y += ufshcd.o ufs-sysfs.o ufs-mcq.o ufshcd-core-$(CONFIG_DEBUG_FS) += ufs-debugfs.o ufshcd-core-$(CONFIG_SCSI_UFS_BSG) += ufs_bsg.o ufshcd-core-$(CONFIG_SCSI_UFS_CRYPTO) += ufshcd-crypto.o -ufshcd-core-$(CONFIG_SCSI_UFS_HPB) += ufshpb.o ufshcd-core-$(CONFIG_SCSI_UFS_FAULT_INJECTION) += ufs-fault-injection.o ufshcd-core-$(CONFIG_SCSI_UFS_HWMON) += ufs-hwmon.o diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c index 6c72075750dd0..c95906443d5f9 100644 --- a/drivers/ufs/core/ufs-sysfs.c +++ b/drivers/ufs/core/ufs-sysfs.c @@ -718,8 +718,6 @@ UFS_DEVICE_DESC_PARAM(device_version, _DEV_VER, 2); UFS_DEVICE_DESC_PARAM(number_of_secure_wpa, _NUM_SEC_WPA, 1); UFS_DEVICE_DESC_PARAM(psa_max_data_size, _PSA_MAX_DATA, 4); UFS_DEVICE_DESC_PARAM(psa_state_timeout, _PSA_TMT, 1); -UFS_DEVICE_DESC_PARAM(hpb_version, _HPB_VER, 2); -UFS_DEVICE_DESC_PARAM(hpb_control, _HPB_CONTROL, 1); UFS_DEVICE_DESC_PARAM(ext_feature_sup, _EXT_UFS_FEATURE_SUP, 4); UFS_DEVICE_DESC_PARAM(wb_presv_us_en, _WB_PRESRV_USRSPC_EN, 1); UFS_DEVICE_DESC_PARAM(wb_type, _WB_TYPE, 1); @@ -752,8 +750,6 @@ static struct attribute *ufs_sysfs_device_descriptor[] = { &dev_attr_number_of_secure_wpa.attr, &dev_attr_psa_max_data_size.attr, &dev_attr_psa_state_timeout.attr, - &dev_attr_hpb_version.attr, - &dev_attr_hpb_control.attr, &dev_attr_ext_feature_sup.attr, &dev_attr_wb_presv_us_en.attr, &dev_attr_wb_type.attr, @@ -827,10 +823,6 @@ UFS_GEOMETRY_DESC_PARAM(enh4_memory_max_alloc_units, _ENM4_MAX_NUM_UNITS, 4); UFS_GEOMETRY_DESC_PARAM(enh4_memory_capacity_adjustment_factor, _ENM4_CAP_ADJ_FCTR, 2); -UFS_GEOMETRY_DESC_PARAM(hpb_region_size, _HPB_REGION_SIZE, 1); -UFS_GEOMETRY_DESC_PARAM(hpb_number_lu, _HPB_NUMBER_LU, 1); -UFS_GEOMETRY_DESC_PARAM(hpb_subregion_size, _HPB_SUBREGION_SIZE, 1); -UFS_GEOMETRY_DESC_PARAM(hpb_max_active_regions, _HPB_MAX_ACTIVE_REGS, 2); UFS_GEOMETRY_DESC_PARAM(wb_max_alloc_units, _WB_MAX_ALLOC_UNITS, 4); UFS_GEOMETRY_DESC_PARAM(wb_max_wb_luns, _WB_MAX_WB_LUNS, 1); UFS_GEOMETRY_DESC_PARAM(wb_buff_cap_adj, _WB_BUFF_CAP_ADJ, 1); @@ -868,10 +860,6 @@ static struct attribute *ufs_sysfs_geometry_descriptor[] = { &dev_attr_enh3_memory_capacity_adjustment_factor.attr, &dev_attr_enh4_memory_max_alloc_units.attr, &dev_attr_enh4_memory_capacity_adjustment_factor.attr, - &dev_attr_hpb_region_size.attr, - &dev_attr_hpb_number_lu.attr, - &dev_attr_hpb_subregion_size.attr, - &dev_attr_hpb_max_active_regions.attr, &dev_attr_wb_max_alloc_units.attr, &dev_attr_wb_max_wb_luns.attr, &dev_attr_wb_buff_cap_adj.attr, @@ -1132,7 +1120,6 @@ UFS_FLAG(disable_fw_update, _PERMANENTLY_DISABLE_FW_UPDATE); UFS_FLAG(wb_enable, _WB_EN); UFS_FLAG(wb_flush_en, _WB_BUFF_FLUSH_EN); UFS_FLAG(wb_flush_during_h8, _WB_BUFF_FLUSH_DURING_HIBERN8); -UFS_FLAG(hpb_enable, _HPB_EN); static struct attribute *ufs_sysfs_device_flags[] = { &dev_attr_device_init.attr, @@ -1146,7 +1133,6 @@ static struct attribute *ufs_sysfs_device_flags[] = { &dev_attr_wb_enable.attr, &dev_attr_wb_flush_en.attr, &dev_attr_wb_flush_during_h8.attr, - &dev_attr_hpb_enable.attr, NULL, }; @@ -1193,7 +1179,6 @@ out: \ static DEVICE_ATTR_RO(_name) UFS_ATTRIBUTE(boot_lun_enabled, _BOOT_LU_EN); -UFS_ATTRIBUTE(max_data_size_hpb_single_cmd, _MAX_HPB_SINGLE_CMD); UFS_ATTRIBUTE(current_power_mode, _POWER_MODE); UFS_ATTRIBUTE(active_icc_level, _ACTIVE_ICC_LVL); UFS_ATTRIBUTE(ooo_data_enabled, _OOO_DATA_EN); @@ -1217,7 +1202,6 @@ UFS_ATTRIBUTE(wb_cur_buf, _CURR_WB_BUFF_SIZE); static struct attribute *ufs_sysfs_attributes[] = { &dev_attr_boot_lun_enabled.attr, - &dev_attr_max_data_size_hpb_single_cmd.attr, &dev_attr_current_power_mode.attr, &dev_attr_active_icc_level.attr, &dev_attr_ooo_data_enabled.attr, @@ -1291,9 +1275,6 @@ UFS_UNIT_DESC_PARAM(provisioning_type, _PROVISIONING_TYPE, 1); UFS_UNIT_DESC_PARAM(physical_memory_resourse_count, _PHY_MEM_RSRC_CNT, 8); UFS_UNIT_DESC_PARAM(context_capabilities, _CTX_CAPABILITIES, 2); UFS_UNIT_DESC_PARAM(large_unit_granularity, _LARGE_UNIT_SIZE_M1, 1); -UFS_UNIT_DESC_PARAM(hpb_lu_max_active_regions, _HPB_LU_MAX_ACTIVE_RGNS, 2); -UFS_UNIT_DESC_PARAM(hpb_pinned_region_start_offset, _HPB_PIN_RGN_START_OFF, 2); -UFS_UNIT_DESC_PARAM(hpb_number_pinned_regions, _HPB_NUM_PIN_RGNS, 2); UFS_UNIT_DESC_PARAM(wb_buf_alloc_units, _WB_BUF_ALLOC_UNITS, 4); static struct attribute *ufs_sysfs_unit_descriptor[] = { @@ -1311,9 +1292,6 @@ static struct attribute *ufs_sysfs_unit_descriptor[] = { &dev_attr_physical_memory_resourse_count.attr, &dev_attr_context_capabilities.attr, &dev_attr_large_unit_granularity.attr, - &dev_attr_hpb_lu_max_active_regions.attr, - &dev_attr_hpb_pinned_region_start_offset.attr, - &dev_attr_hpb_number_pinned_regions.attr, &dev_attr_wb_buf_alloc_units.attr, NULL, }; diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index f00375daaf99f..c394dc50504ad 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -34,7 +34,6 @@ #include "ufs-fault-injection.h" #include "ufs_bsg.h" #include "ufshcd-crypto.h" -#include "ufshpb.h" #include #define CREATE_TRACE_POINTS @@ -238,8 +237,7 @@ static const struct ufs_dev_quirk ufs_fixups[] = { /* UFS cards deviations table */ { .wmanufacturerid = UFS_VENDOR_MICRON, .model = UFS_ANY_MODEL, - .quirk = UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM | - UFS_DEVICE_QUIRK_SWAP_L2P_ENTRY_FOR_HPB_READ }, + .quirk = UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM }, { .wmanufacturerid = UFS_VENDOR_SAMSUNG, .model = UFS_ANY_MODEL, .quirk = UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM | @@ -2907,8 +2905,6 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) lrbp->req_abort_skip = false; - ufshpb_prep(hba, lrbp); - ufshcd_comp_scsi_upiu(hba, lrbp); err = ufshcd_map_sg(hba, lrbp); @@ -5107,26 +5103,6 @@ static int ufshcd_change_queue_depth(struct scsi_device *sdev, int depth) return scsi_change_queue_depth(sdev, min(depth, sdev->host->can_queue)); } -static void ufshcd_hpb_destroy(struct ufs_hba *hba, struct scsi_device *sdev) -{ - /* skip well-known LU */ - if ((sdev->lun >= UFS_UPIU_MAX_UNIT_NUM_ID) || - !(hba->dev_info.hpb_enabled) || !ufshpb_is_allowed(hba)) - return; - - ufshpb_destroy_lu(hba, sdev); -} - -static void ufshcd_hpb_configure(struct ufs_hba *hba, struct scsi_device *sdev) -{ - /* skip well-known LU */ - if ((sdev->lun >= UFS_UPIU_MAX_UNIT_NUM_ID) || - !(hba->dev_info.hpb_enabled) || !ufshpb_is_allowed(hba)) - return; - - ufshpb_init_hpb_lu(hba, sdev); -} - /** * ufshcd_slave_configure - adjust SCSI device configurations * @sdev: pointer to SCSI device @@ -5136,8 +5112,6 @@ static int ufshcd_slave_configure(struct scsi_device *sdev) struct ufs_hba *hba = shost_priv(sdev->host); struct request_queue *q = sdev->request_queue; - ufshcd_hpb_configure(hba, sdev); - blk_queue_update_dma_pad(q, PRDT_DATA_BYTE_COUNT_PAD - 1); if (hba->quirks & UFSHCD_QUIRK_4KB_DMA_ALIGNMENT) blk_queue_update_dma_alignment(q, SZ_4K - 1); @@ -5172,8 +5146,6 @@ static void ufshcd_slave_destroy(struct scsi_device *sdev) hba = shost_priv(sdev->host); - ufshcd_hpb_destroy(hba, sdev); - /* Drop the reference as it won't be needed anymore */ if (ufshcd_scsi_to_upiu_lun(sdev->lun) == UFS_UPIU_UFS_DEVICE_WLUN) { spin_lock_irqsave(hba->host->host_lock, flags); @@ -5299,9 +5271,6 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, ufshcd_is_exception_event(lrbp->ucd_rsp_ptr)) /* Flushed in suspend */ schedule_work(&hba->eeh_work); - - if (scsi_status == SAM_STAT_GOOD) - ufshpb_rsp_upiu(hba, lrbp); break; case UPIU_TRANSACTION_REJECT_UPIU: /* TODO: handle Reject UPIU Response */ @@ -7658,7 +7627,6 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba) * Stop the host controller and complete the requests * cleared by h/w */ - ufshpb_toggle_state(hba, HPB_PRESENT, HPB_RESET); ufshcd_hba_stop(hba); hba->silence_err_logs = true; ufshcd_complete_requests(hba, true); @@ -8121,7 +8089,6 @@ static int ufs_get_device_desc(struct ufs_hba *hba) { int err; u8 model_index; - u8 b_ufs_feature_sup; u8 *desc_buf; struct ufs_dev_info *dev_info = &hba->dev_info; @@ -8150,26 +8117,9 @@ static int ufs_get_device_desc(struct ufs_hba *hba) dev_info->wspecversion = desc_buf[DEVICE_DESC_PARAM_SPEC_VER] << 8 | desc_buf[DEVICE_DESC_PARAM_SPEC_VER + 1]; dev_info->bqueuedepth = desc_buf[DEVICE_DESC_PARAM_Q_DPTH]; - b_ufs_feature_sup = desc_buf[DEVICE_DESC_PARAM_UFS_FEAT]; model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; - if (dev_info->wspecversion >= UFS_DEV_HPB_SUPPORT_VERSION && - (b_ufs_feature_sup & UFS_DEV_HPB_SUPPORT)) { - bool hpb_en = false; - - ufshpb_get_dev_info(hba, desc_buf); - - if (!ufshpb_is_legacy(hba)) - err = ufshcd_query_flag_retry(hba, - UPIU_QUERY_OPCODE_READ_FLAG, - QUERY_FLAG_IDN_HPB_EN, 0, - &hpb_en); - - if (ufshpb_is_legacy(hba) || (!err && hpb_en)) - dev_info->hpb_enabled = true; - } - err = ufshcd_read_string_desc(hba, model_index, &dev_info->model, SD_ASCII_STD); if (err < 0) { @@ -8404,10 +8354,6 @@ static int ufshcd_device_geo_params_init(struct ufs_hba *hba) else if (desc_buf[GEOMETRY_DESC_PARAM_MAX_NUM_LUN] == 0) hba->dev_info.max_lu_supported = 8; - if (desc_buf[QUERY_DESC_LENGTH_OFFSET] >= - GEOMETRY_DESC_PARAM_HPB_MAX_ACTIVE_REGS) - ufshpb_get_geo_info(hba, desc_buf); - out: kfree(desc_buf); return err; @@ -8548,7 +8494,6 @@ static int ufshcd_add_lus(struct ufs_hba *hba) } ufs_bsg_probe(hba); - ufshpb_init(hba); scsi_scan_host(hba->host); pm_runtime_put_sync(hba->dev); @@ -8780,7 +8725,6 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) /* Enable Auto-Hibernate if configured */ ufshcd_auto_hibern8_enable(hba); - ufshpb_toggle_state(hba, HPB_RESET, HPB_PRESENT); out: spin_lock_irqsave(hba->host->host_lock, flags); if (ret) @@ -8850,10 +8794,6 @@ static enum scsi_timeout_action ufshcd_eh_timed_out(struct scsi_cmnd *scmd) static const struct attribute_group *ufshcd_driver_groups[] = { &ufs_sysfs_unit_descriptor_group, &ufs_sysfs_lun_attributes_group, -#ifdef CONFIG_SCSI_UFS_HPB - &ufs_sysfs_hpb_stat_group, - &ufs_sysfs_hpb_param_group, -#endif NULL, }; @@ -9538,8 +9478,6 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) req_link_state = UIC_LINK_OFF_STATE; } - ufshpb_suspend(hba); - /* * If we can't transition into any of the low power modes * just gate the clocks. @@ -9693,7 +9631,6 @@ out: ufshcd_update_evt_hist(hba, UFS_EVT_WL_SUSP_ERR, (u32)ret); hba->clk_gating.is_suspended = false; ufshcd_release(hba); - ufshpb_resume(hba); } hba->pm_op_in_progress = false; return ret; @@ -9773,7 +9710,6 @@ static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) /* Enable Auto-Hibernate if configured */ ufshcd_auto_hibern8_enable(hba); - ufshpb_resume(hba); goto out; set_old_link_state: @@ -10113,7 +10049,6 @@ void ufshcd_remove(struct ufs_hba *hba) ufshcd_rpm_get_sync(hba); ufs_hwmon_remove(hba); ufs_bsg_remove(hba); - ufshpb_remove(hba); ufs_sysfs_remove_nodes(hba->dev); blk_mq_destroy_queue(hba->tmf_queue); blk_put_queue(hba->tmf_queue); diff --git a/drivers/ufs/core/ufshpb.c b/drivers/ufs/core/ufshpb.c deleted file mode 100644 index 92398db10e33c..0000000000000 --- a/drivers/ufs/core/ufshpb.c +++ /dev/null @@ -1,2668 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Universal Flash Storage Host Performance Booster - * - * Copyright (C) 2017-2021 Samsung Electronics Co., Ltd. - * - * Authors: - * Yongmyung Lee - * Jinyoung Choi - */ - -#include -#include -#include -#include -#include - -#include "ufshcd-priv.h" -#include "ufshpb.h" -#include "../../scsi/sd.h" - -#define ACTIVATION_THRESHOLD 8 /* 8 IOs */ -#define READ_TO_MS 1000 -#define READ_TO_EXPIRIES 100 -#define POLLING_INTERVAL_MS 200 -#define THROTTLE_MAP_REQ_DEFAULT 1 - -/* memory management */ -static struct kmem_cache *ufshpb_mctx_cache; -static mempool_t *ufshpb_mctx_pool; -static mempool_t *ufshpb_page_pool; -/* A cache size of 2MB can cache ppn in the 1GB range. */ -static unsigned int ufshpb_host_map_kbytes = SZ_2K; -static int tot_active_srgn_pages; - -static struct workqueue_struct *ufshpb_wq; - -static void ufshpb_update_active_info(struct ufshpb_lu *hpb, int rgn_idx, - int srgn_idx); - -bool ufshpb_is_allowed(struct ufs_hba *hba) -{ - return !(hba->ufshpb_dev.hpb_disabled); -} - -/* HPB version 1.0 is called as legacy version. */ -bool ufshpb_is_legacy(struct ufs_hba *hba) -{ - return hba->ufshpb_dev.is_legacy; -} - -static struct ufshpb_lu *ufshpb_get_hpb_data(struct scsi_device *sdev) -{ - return sdev->hostdata; -} - -static int ufshpb_get_state(struct ufshpb_lu *hpb) -{ - return atomic_read(&hpb->hpb_state); -} - -static void ufshpb_set_state(struct ufshpb_lu *hpb, int state) -{ - atomic_set(&hpb->hpb_state, state); -} - -static int ufshpb_is_valid_srgn(struct ufshpb_region *rgn, - struct ufshpb_subregion *srgn) -{ - return rgn->rgn_state != HPB_RGN_INACTIVE && - srgn->srgn_state == HPB_SRGN_VALID; -} - -static bool ufshpb_is_read_cmd(struct scsi_cmnd *cmd) -{ - return req_op(scsi_cmd_to_rq(cmd)) == REQ_OP_READ; -} - -static bool ufshpb_is_write_or_discard(struct scsi_cmnd *cmd) -{ - return op_is_write(req_op(scsi_cmd_to_rq(cmd))) || - op_is_discard(req_op(scsi_cmd_to_rq(cmd))); -} - -static bool ufshpb_is_supported_chunk(struct ufshpb_lu *hpb, int transfer_len) -{ - return transfer_len <= hpb->pre_req_max_tr_len; -} - -static bool ufshpb_is_general_lun(int lun) -{ - return lun < UFS_UPIU_MAX_UNIT_NUM_ID; -} - -static bool ufshpb_is_pinned_region(struct ufshpb_lu *hpb, int rgn_idx) -{ - return hpb->lu_pinned_end != PINNED_NOT_SET && - rgn_idx >= hpb->lu_pinned_start && rgn_idx <= hpb->lu_pinned_end; -} - -static void ufshpb_kick_map_work(struct ufshpb_lu *hpb) -{ - bool ret = false; - unsigned long flags; - - if (ufshpb_get_state(hpb) != HPB_PRESENT) - return; - - spin_lock_irqsave(&hpb->rsp_list_lock, flags); - if (!list_empty(&hpb->lh_inact_rgn) || !list_empty(&hpb->lh_act_srgn)) - ret = true; - spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); - - if (ret) - queue_work(ufshpb_wq, &hpb->map_work); -} - -static bool ufshpb_is_hpb_rsp_valid(struct ufs_hba *hba, - struct ufshcd_lrb *lrbp, - struct utp_hpb_rsp *rsp_field) -{ - /* Check HPB_UPDATE_ALERT */ - if (!(lrbp->ucd_rsp_ptr->header.dword_2 & - upiu_header_dword(0, 2, 0, 0))) - return false; - - if (be16_to_cpu(rsp_field->sense_data_len) != DEV_SENSE_SEG_LEN || - rsp_field->desc_type != DEV_DES_TYPE || - rsp_field->additional_len != DEV_ADDITIONAL_LEN || - rsp_field->active_rgn_cnt > MAX_ACTIVE_NUM || - rsp_field->inactive_rgn_cnt > MAX_INACTIVE_NUM || - rsp_field->hpb_op == HPB_RSP_NONE || - (rsp_field->hpb_op == HPB_RSP_REQ_REGION_UPDATE && - !rsp_field->active_rgn_cnt && !rsp_field->inactive_rgn_cnt)) - return false; - - if (!ufshpb_is_general_lun(rsp_field->lun)) { - dev_warn(hba->dev, "ufshpb: lun(%d) not supported\n", - lrbp->lun); - return false; - } - - return true; -} - -static void ufshpb_iterate_rgn(struct ufshpb_lu *hpb, int rgn_idx, int srgn_idx, - int srgn_offset, int cnt, bool set_dirty) -{ - struct ufshpb_region *rgn; - struct ufshpb_subregion *srgn, *prev_srgn = NULL; - int set_bit_len; - int bitmap_len; - unsigned long flags; - -next_srgn: - rgn = hpb->rgn_tbl + rgn_idx; - srgn = rgn->srgn_tbl + srgn_idx; - - if (likely(!srgn->is_last)) - bitmap_len = hpb->entries_per_srgn; - else - bitmap_len = hpb->last_srgn_entries; - - if ((srgn_offset + cnt) > bitmap_len) - set_bit_len = bitmap_len - srgn_offset; - else - set_bit_len = cnt; - - spin_lock_irqsave(&hpb->rgn_state_lock, flags); - if (rgn->rgn_state != HPB_RGN_INACTIVE) { - if (set_dirty) { - if (srgn->srgn_state == HPB_SRGN_VALID) - bitmap_set(srgn->mctx->ppn_dirty, srgn_offset, - set_bit_len); - } else if (hpb->is_hcm) { - /* rewind the read timer for lru regions */ - rgn->read_timeout = ktime_add_ms(ktime_get(), - rgn->hpb->params.read_timeout_ms); - rgn->read_timeout_expiries = - rgn->hpb->params.read_timeout_expiries; - } - } - spin_unlock_irqrestore(&hpb->rgn_state_lock, flags); - - if (hpb->is_hcm && prev_srgn != srgn) { - bool activate = false; - - spin_lock(&rgn->rgn_lock); - if (set_dirty) { - rgn->reads -= srgn->reads; - srgn->reads = 0; - set_bit(RGN_FLAG_DIRTY, &rgn->rgn_flags); - } else { - srgn->reads++; - rgn->reads++; - if (srgn->reads == hpb->params.activation_thld) - activate = true; - } - spin_unlock(&rgn->rgn_lock); - - if (activate || - test_and_clear_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags)) { - spin_lock_irqsave(&hpb->rsp_list_lock, flags); - ufshpb_update_active_info(hpb, rgn_idx, srgn_idx); - spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); - dev_dbg(&hpb->sdev_ufs_lu->sdev_dev, - "activate region %d-%d\n", rgn_idx, srgn_idx); - } - - prev_srgn = srgn; - } - - srgn_offset = 0; - if (++srgn_idx == hpb->srgns_per_rgn) { - srgn_idx = 0; - rgn_idx++; - } - - cnt -= set_bit_len; - if (cnt > 0) - goto next_srgn; -} - -static bool ufshpb_test_ppn_dirty(struct ufshpb_lu *hpb, int rgn_idx, - int srgn_idx, int srgn_offset, int cnt) -{ - struct ufshpb_region *rgn; - struct ufshpb_subregion *srgn; - int bitmap_len; - int bit_len; - -next_srgn: - rgn = hpb->rgn_tbl + rgn_idx; - srgn = rgn->srgn_tbl + srgn_idx; - - if (!ufshpb_is_valid_srgn(rgn, srgn)) - return true; - - /* - * If the region state is active, mctx must be allocated. - * In this case, check whether the region is evicted or - * mctx allocation fail. - */ - if (unlikely(!srgn->mctx)) { - dev_err(&hpb->sdev_ufs_lu->sdev_dev, - "no mctx in region %d subregion %d.\n", - srgn->rgn_idx, srgn->srgn_idx); - return true; - } - - if (likely(!srgn->is_last)) - bitmap_len = hpb->entries_per_srgn; - else - bitmap_len = hpb->last_srgn_entries; - - if ((srgn_offset + cnt) > bitmap_len) - bit_len = bitmap_len - srgn_offset; - else - bit_len = cnt; - - if (find_next_bit(srgn->mctx->ppn_dirty, bit_len + srgn_offset, - srgn_offset) < bit_len + srgn_offset) - return true; - - srgn_offset = 0; - if (++srgn_idx == hpb->srgns_per_rgn) { - srgn_idx = 0; - rgn_idx++; - } - - cnt -= bit_len; - if (cnt > 0) - goto next_srgn; - - return false; -} - -static inline bool is_rgn_dirty(struct ufshpb_region *rgn) -{ - return test_bit(RGN_FLAG_DIRTY, &rgn->rgn_flags); -} - -static int ufshpb_fill_ppn_from_page(struct ufshpb_lu *hpb, - struct ufshpb_map_ctx *mctx, int pos, - int len, __be64 *ppn_buf) -{ - struct page *page; - int index, offset; - int copied; - - index = pos / (PAGE_SIZE / HPB_ENTRY_SIZE); - offset = pos % (PAGE_SIZE / HPB_ENTRY_SIZE); - - if ((offset + len) <= (PAGE_SIZE / HPB_ENTRY_SIZE)) - copied = len; - else - copied = (PAGE_SIZE / HPB_ENTRY_SIZE) - offset; - - page = mctx->m_page[index]; - if (unlikely(!page)) { - dev_err(&hpb->sdev_ufs_lu->sdev_dev, - "error. cannot find page in mctx\n"); - return -ENOMEM; - } - - memcpy(ppn_buf, page_address(page) + (offset * HPB_ENTRY_SIZE), - copied * HPB_ENTRY_SIZE); - - return copied; -} - -static void -ufshpb_get_pos_from_lpn(struct ufshpb_lu *hpb, unsigned long lpn, int *rgn_idx, - int *srgn_idx, int *offset) -{ - int rgn_offset; - - *rgn_idx = lpn >> hpb->entries_per_rgn_shift; - rgn_offset = lpn & hpb->entries_per_rgn_mask; - *srgn_idx = rgn_offset >> hpb->entries_per_srgn_shift; - *offset = rgn_offset & hpb->entries_per_srgn_mask; -} - -static void -ufshpb_set_hpb_read_to_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, - __be64 ppn, u8 transfer_len) -{ - unsigned char *cdb = lrbp->cmd->cmnd; - __be64 ppn_tmp = ppn; - cdb[0] = UFSHPB_READ; - - if (hba->dev_quirks & UFS_DEVICE_QUIRK_SWAP_L2P_ENTRY_FOR_HPB_READ) - ppn_tmp = (__force __be64)swab64((__force u64)ppn); - - /* ppn value is stored as big-endian in the host memory */ - memcpy(&cdb[6], &ppn_tmp, sizeof(__be64)); - cdb[14] = transfer_len; - cdb[15] = 0; - - lrbp->cmd->cmd_len = UFS_CDB_SIZE; -} - -/* - * This function will set up HPB read command using host-side L2P map data. - */ -int ufshpb_prep(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) -{ - struct ufshpb_lu *hpb; - struct ufshpb_region *rgn; - struct ufshpb_subregion *srgn; - struct scsi_cmnd *cmd = lrbp->cmd; - u32 lpn; - __be64 ppn; - unsigned long flags; - int transfer_len, rgn_idx, srgn_idx, srgn_offset; - int err = 0; - - hpb = ufshpb_get_hpb_data(cmd->device); - if (!hpb) - return -ENODEV; - - if (ufshpb_get_state(hpb) == HPB_INIT) - return -ENODEV; - - if (ufshpb_get_state(hpb) != HPB_PRESENT) { - dev_notice(&hpb->sdev_ufs_lu->sdev_dev, - "%s: ufshpb state is not PRESENT", __func__); - return -ENODEV; - } - - if (blk_rq_is_passthrough(scsi_cmd_to_rq(cmd)) || - (!ufshpb_is_write_or_discard(cmd) && - !ufshpb_is_read_cmd(cmd))) - return 0; - - transfer_len = sectors_to_logical(cmd->device, - blk_rq_sectors(scsi_cmd_to_rq(cmd))); - if (unlikely(!transfer_len)) - return 0; - - lpn = sectors_to_logical(cmd->device, blk_rq_pos(scsi_cmd_to_rq(cmd))); - ufshpb_get_pos_from_lpn(hpb, lpn, &rgn_idx, &srgn_idx, &srgn_offset); - rgn = hpb->rgn_tbl + rgn_idx; - srgn = rgn->srgn_tbl + srgn_idx; - - /* If command type is WRITE or DISCARD, set bitmap as dirty */ - if (ufshpb_is_write_or_discard(cmd)) { - ufshpb_iterate_rgn(hpb, rgn_idx, srgn_idx, srgn_offset, - transfer_len, true); - return 0; - } - - if (!ufshpb_is_supported_chunk(hpb, transfer_len)) - return 0; - - if (hpb->is_hcm) { - /* - * in host control mode, reads are the main source for - * activation trials. - */ - ufshpb_iterate_rgn(hpb, rgn_idx, srgn_idx, srgn_offset, - transfer_len, false); - - /* keep those counters normalized */ - if (rgn->reads > hpb->entries_per_srgn) - schedule_work(&hpb->ufshpb_normalization_work); - } - - spin_lock_irqsave(&hpb->rgn_state_lock, flags); - if (ufshpb_test_ppn_dirty(hpb, rgn_idx, srgn_idx, srgn_offset, - transfer_len)) { - hpb->stats.miss_cnt++; - spin_unlock_irqrestore(&hpb->rgn_state_lock, flags); - return 0; - } - - err = ufshpb_fill_ppn_from_page(hpb, srgn->mctx, srgn_offset, 1, &ppn); - spin_unlock_irqrestore(&hpb->rgn_state_lock, flags); - if (unlikely(err < 0)) { - /* - * In this case, the region state is active, - * but the ppn table is not allocated. - * Make sure that ppn table must be allocated on - * active state. - */ - dev_err(hba->dev, "get ppn failed. err %d\n", err); - return err; - } - - ufshpb_set_hpb_read_to_upiu(hba, lrbp, ppn, transfer_len); - - hpb->stats.hit_cnt++; - return 0; -} - -static struct ufshpb_req *ufshpb_get_req(struct ufshpb_lu *hpb, int rgn_idx, - enum req_op op, bool atomic) -{ - struct ufshpb_req *rq; - struct request *req; - int retries = HPB_MAP_REQ_RETRIES; - - rq = kmem_cache_alloc(hpb->map_req_cache, GFP_KERNEL); - if (!rq) - return NULL; - -retry: - req = blk_mq_alloc_request(hpb->sdev_ufs_lu->request_queue, op, - BLK_MQ_REQ_NOWAIT); - - if (!atomic && (PTR_ERR(req) == -EWOULDBLOCK) && (--retries > 0)) { - usleep_range(3000, 3100); - goto retry; - } - - if (IS_ERR(req)) - goto free_rq; - - rq->hpb = hpb; - rq->req = req; - rq->rb.rgn_idx = rgn_idx; - - return rq; - -free_rq: - kmem_cache_free(hpb->map_req_cache, rq); - return NULL; -} - -static void ufshpb_put_req(struct ufshpb_lu *hpb, struct ufshpb_req *rq) -{ - blk_mq_free_request(rq->req); - kmem_cache_free(hpb->map_req_cache, rq); -} - -static struct ufshpb_req *ufshpb_get_map_req(struct ufshpb_lu *hpb, - struct ufshpb_subregion *srgn) -{ - struct ufshpb_req *map_req; - struct bio *bio; - unsigned long flags; - - if (hpb->is_hcm && - hpb->num_inflight_map_req >= hpb->params.inflight_map_req) { - dev_info(&hpb->sdev_ufs_lu->sdev_dev, - "map_req throttle. inflight %d throttle %d", - hpb->num_inflight_map_req, - hpb->params.inflight_map_req); - return NULL; - } - - map_req = ufshpb_get_req(hpb, srgn->rgn_idx, REQ_OP_DRV_IN, false); - if (!map_req) - return NULL; - - bio = bio_alloc(NULL, hpb->pages_per_srgn, 0, GFP_KERNEL); - if (!bio) { - ufshpb_put_req(hpb, map_req); - return NULL; - } - - map_req->bio = bio; - - map_req->rb.srgn_idx = srgn->srgn_idx; - map_req->rb.mctx = srgn->mctx; - - spin_lock_irqsave(&hpb->param_lock, flags); - hpb->num_inflight_map_req++; - spin_unlock_irqrestore(&hpb->param_lock, flags); - - return map_req; -} - -static void ufshpb_put_map_req(struct ufshpb_lu *hpb, - struct ufshpb_req *map_req) -{ - unsigned long flags; - - bio_put(map_req->bio); - ufshpb_put_req(hpb, map_req); - - spin_lock_irqsave(&hpb->param_lock, flags); - hpb->num_inflight_map_req--; - spin_unlock_irqrestore(&hpb->param_lock, flags); -} - -static int ufshpb_clear_dirty_bitmap(struct ufshpb_lu *hpb, - struct ufshpb_subregion *srgn) -{ - struct ufshpb_region *rgn; - u32 num_entries = hpb->entries_per_srgn; - - if (!srgn->mctx) { - dev_err(&hpb->sdev_ufs_lu->sdev_dev, - "no mctx in region %d subregion %d.\n", - srgn->rgn_idx, srgn->srgn_idx); - return -1; - } - - if (unlikely(srgn->is_last)) - num_entries = hpb->last_srgn_entries; - - bitmap_zero(srgn->mctx->ppn_dirty, num_entries); - - rgn = hpb->rgn_tbl + srgn->rgn_idx; - clear_bit(RGN_FLAG_DIRTY, &rgn->rgn_flags); - - return 0; -} - -static void ufshpb_update_active_info(struct ufshpb_lu *hpb, int rgn_idx, - int srgn_idx) -{ - struct ufshpb_region *rgn; - struct ufshpb_subregion *srgn; - - rgn = hpb->rgn_tbl + rgn_idx; - srgn = rgn->srgn_tbl + srgn_idx; - - list_del_init(&rgn->list_inact_rgn); - - if (list_empty(&srgn->list_act_srgn)) - list_add_tail(&srgn->list_act_srgn, &hpb->lh_act_srgn); - - hpb->stats.rcmd_active_cnt++; -} - -static void ufshpb_update_inactive_info(struct ufshpb_lu *hpb, int rgn_idx) -{ - struct ufshpb_region *rgn; - struct ufshpb_subregion *srgn; - int srgn_idx; - - rgn = hpb->rgn_tbl + rgn_idx; - - for_each_sub_region(rgn, srgn_idx, srgn) - list_del_init(&srgn->list_act_srgn); - - if (list_empty(&rgn->list_inact_rgn)) - list_add_tail(&rgn->list_inact_rgn, &hpb->lh_inact_rgn); - - hpb->stats.rcmd_inactive_cnt++; -} - -static void ufshpb_activate_subregion(struct ufshpb_lu *hpb, - struct ufshpb_subregion *srgn) -{ - struct ufshpb_region *rgn; - - /* - * If there is no mctx in subregion - * after I/O progress for HPB_READ_BUFFER, the region to which the - * subregion belongs was evicted. - * Make sure the region must not evict in I/O progress - */ - if (!srgn->mctx) { - dev_err(&hpb->sdev_ufs_lu->sdev_dev, - "no mctx in region %d subregion %d.\n", - srgn->rgn_idx, srgn->srgn_idx); - srgn->srgn_state = HPB_SRGN_INVALID; - return; - } - - rgn = hpb->rgn_tbl + srgn->rgn_idx; - - if (unlikely(rgn->rgn_state == HPB_RGN_INACTIVE)) { - dev_err(&hpb->sdev_ufs_lu->sdev_dev, - "region %d subregion %d evicted\n", - srgn->rgn_idx, srgn->srgn_idx); - srgn->srgn_state = HPB_SRGN_INVALID; - return; - } - srgn->srgn_state = HPB_SRGN_VALID; -} - -static enum rq_end_io_ret ufshpb_umap_req_compl_fn(struct request *req, - blk_status_t error) -{ - struct ufshpb_req *umap_req = req->end_io_data; - - ufshpb_put_req(umap_req->hpb, umap_req); - return RQ_END_IO_NONE; -} - -static enum rq_end_io_ret ufshpb_map_req_compl_fn(struct request *req, - blk_status_t error) -{ - struct ufshpb_req *map_req = req->end_io_data; - struct ufshpb_lu *hpb = map_req->hpb; - struct ufshpb_subregion *srgn; - unsigned long flags; - - srgn = hpb->rgn_tbl[map_req->rb.rgn_idx].srgn_tbl + - map_req->rb.srgn_idx; - - ufshpb_clear_dirty_bitmap(hpb, srgn); - spin_lock_irqsave(&hpb->rgn_state_lock, flags); - ufshpb_activate_subregion(hpb, srgn); - spin_unlock_irqrestore(&hpb->rgn_state_lock, flags); - - ufshpb_put_map_req(map_req->hpb, map_req); - return RQ_END_IO_NONE; -} - -static void ufshpb_set_unmap_cmd(unsigned char *cdb, struct ufshpb_region *rgn) -{ - cdb[0] = UFSHPB_WRITE_BUFFER; - cdb[1] = rgn ? UFSHPB_WRITE_BUFFER_INACT_SINGLE_ID : - UFSHPB_WRITE_BUFFER_INACT_ALL_ID; - if (rgn) - put_unaligned_be16(rgn->rgn_idx, &cdb[2]); - cdb[9] = 0x00; -} - -static void ufshpb_set_read_buf_cmd(unsigned char *cdb, int rgn_idx, - int srgn_idx, int srgn_mem_size) -{ - cdb[0] = UFSHPB_READ_BUFFER; - cdb[1] = UFSHPB_READ_BUFFER_ID; - - put_unaligned_be16(rgn_idx, &cdb[2]); - put_unaligned_be16(srgn_idx, &cdb[4]); - put_unaligned_be24(srgn_mem_size, &cdb[6]); - - cdb[9] = 0x00; -} - -static void ufshpb_execute_umap_req(struct ufshpb_lu *hpb, - struct ufshpb_req *umap_req, - struct ufshpb_region *rgn) -{ - struct request *req = umap_req->req; - struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(req); - - req->timeout = 0; - req->end_io_data = umap_req; - req->end_io = ufshpb_umap_req_compl_fn; - - ufshpb_set_unmap_cmd(scmd->cmnd, rgn); - scmd->cmd_len = HPB_WRITE_BUFFER_CMD_LENGTH; - - blk_execute_rq_nowait(req, true); - - hpb->stats.umap_req_cnt++; -} - -static int ufshpb_execute_map_req(struct ufshpb_lu *hpb, - struct ufshpb_req *map_req, bool last) -{ - struct request_queue *q; - struct request *req; - struct scsi_cmnd *scmd; - int mem_size = hpb->srgn_mem_size; - int ret = 0; - int i; - - q = hpb->sdev_ufs_lu->request_queue; - for (i = 0; i < hpb->pages_per_srgn; i++) { - ret = bio_add_pc_page(q, map_req->bio, map_req->rb.mctx->m_page[i], - PAGE_SIZE, 0); - if (ret != PAGE_SIZE) { - dev_err(&hpb->sdev_ufs_lu->sdev_dev, - "bio_add_pc_page fail %d - %d\n", - map_req->rb.rgn_idx, map_req->rb.srgn_idx); - return ret; - } - } - - req = map_req->req; - - blk_rq_append_bio(req, map_req->bio); - - req->end_io_data = map_req; - req->end_io = ufshpb_map_req_compl_fn; - - if (unlikely(last)) - mem_size = hpb->last_srgn_entries * HPB_ENTRY_SIZE; - - scmd = blk_mq_rq_to_pdu(req); - ufshpb_set_read_buf_cmd(scmd->cmnd, map_req->rb.rgn_idx, - map_req->rb.srgn_idx, mem_size); - scmd->cmd_len = HPB_READ_BUFFER_CMD_LENGTH; - - blk_execute_rq_nowait(req, true); - - hpb->stats.map_req_cnt++; - return 0; -} - -static struct ufshpb_map_ctx *ufshpb_get_map_ctx(struct ufshpb_lu *hpb, - bool last) -{ - struct ufshpb_map_ctx *mctx; - u32 num_entries = hpb->entries_per_srgn; - int i, j; - - mctx = mempool_alloc(ufshpb_mctx_pool, GFP_KERNEL); - if (!mctx) - return NULL; - - mctx->m_page = kmem_cache_alloc(hpb->m_page_cache, GFP_KERNEL); - if (!mctx->m_page) - goto release_mctx; - - if (unlikely(last)) - num_entries = hpb->last_srgn_entries; - - mctx->ppn_dirty = bitmap_zalloc(num_entries, GFP_KERNEL); - if (!mctx->ppn_dirty) - goto release_m_page; - - for (i = 0; i < hpb->pages_per_srgn; i++) { - mctx->m_page[i] = mempool_alloc(ufshpb_page_pool, GFP_KERNEL); - if (!mctx->m_page[i]) { - for (j = 0; j < i; j++) - mempool_free(mctx->m_page[j], ufshpb_page_pool); - goto release_ppn_dirty; - } - clear_page(page_address(mctx->m_page[i])); - } - - return mctx; - -release_ppn_dirty: - bitmap_free(mctx->ppn_dirty); -release_m_page: - kmem_cache_free(hpb->m_page_cache, mctx->m_page); -release_mctx: - mempool_free(mctx, ufshpb_mctx_pool); - return NULL; -} - -static void ufshpb_put_map_ctx(struct ufshpb_lu *hpb, - struct ufshpb_map_ctx *mctx) -{ - int i; - - for (i = 0; i < hpb->pages_per_srgn; i++) - mempool_free(mctx->m_page[i], ufshpb_page_pool); - - bitmap_free(mctx->ppn_dirty); - kmem_cache_free(hpb->m_page_cache, mctx->m_page); - mempool_free(mctx, ufshpb_mctx_pool); -} - -static int ufshpb_check_srgns_issue_state(struct ufshpb_lu *hpb, - struct ufshpb_region *rgn) -{ - struct ufshpb_subregion *srgn; - int srgn_idx; - - for_each_sub_region(rgn, srgn_idx, srgn) - if (srgn->srgn_state == HPB_SRGN_ISSUED) - return -EPERM; - - return 0; -} - -static void ufshpb_read_to_handler(struct work_struct *work) -{ - struct ufshpb_lu *hpb = container_of(work, struct ufshpb_lu, - ufshpb_read_to_work.work); - struct victim_select_info *lru_info = &hpb->lru_info; - struct ufshpb_region *rgn, *next_rgn; - unsigned long flags; - unsigned int poll; - LIST_HEAD(expired_list); - - if (test_and_set_bit(TIMEOUT_WORK_RUNNING, &hpb->work_data_bits)) - return; - - spin_lock_irqsave(&hpb->rgn_state_lock, flags); - - list_for_each_entry_safe(rgn, next_rgn, &lru_info->lh_lru_rgn, - list_lru_rgn) { - bool timedout = ktime_after(ktime_get(), rgn->read_timeout); - - if (timedout) { - rgn->read_timeout_expiries--; - if (is_rgn_dirty(rgn) || - rgn->read_timeout_expiries == 0) - list_add(&rgn->list_expired_rgn, &expired_list); - else - rgn->read_timeout = ktime_add_ms(ktime_get(), - hpb->params.read_timeout_ms); - } - } - - spin_unlock_irqrestore(&hpb->rgn_state_lock, flags); - - list_for_each_entry_safe(rgn, next_rgn, &expired_list, - list_expired_rgn) { - list_del_init(&rgn->list_expired_rgn); - spin_lock_irqsave(&hpb->rsp_list_lock, flags); - ufshpb_update_inactive_info(hpb, rgn->rgn_idx); - spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); - } - - ufshpb_kick_map_work(hpb); - - clear_bit(TIMEOUT_WORK_RUNNING, &hpb->work_data_bits); - - poll = hpb->params.timeout_polling_interval_ms; - schedule_delayed_work(&hpb->ufshpb_read_to_work, - msecs_to_jiffies(poll)); -} - -static void ufshpb_add_lru_info(struct victim_select_info *lru_info, - struct ufshpb_region *rgn) -{ - rgn->rgn_state = HPB_RGN_ACTIVE; - list_add_tail(&rgn->list_lru_rgn, &lru_info->lh_lru_rgn); - atomic_inc(&lru_info->active_cnt); - if (rgn->hpb->is_hcm) { - rgn->read_timeout = - ktime_add_ms(ktime_get(), - rgn->hpb->params.read_timeout_ms); - rgn->read_timeout_expiries = - rgn->hpb->params.read_timeout_expiries; - } -} - -static void ufshpb_hit_lru_info(struct victim_select_info *lru_info, - struct ufshpb_region *rgn) -{ - list_move_tail(&rgn->list_lru_rgn, &lru_info->lh_lru_rgn); -} - -static struct ufshpb_region *ufshpb_victim_lru_info(struct ufshpb_lu *hpb) -{ - struct victim_select_info *lru_info = &hpb->lru_info; - struct ufshpb_region *rgn, *victim_rgn = NULL; - - list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn) { - if (ufshpb_check_srgns_issue_state(hpb, rgn)) - continue; - - /* - * in host control mode, verify that the exiting region - * has fewer reads - */ - if (hpb->is_hcm && - rgn->reads > hpb->params.eviction_thld_exit) - continue; - - victim_rgn = rgn; - break; - } - - if (!victim_rgn) - dev_err(&hpb->sdev_ufs_lu->sdev_dev, - "%s: no region allocated\n", - __func__); - - return victim_rgn; -} - -static void ufshpb_cleanup_lru_info(struct victim_select_info *lru_info, - struct ufshpb_region *rgn) -{ - list_del_init(&rgn->list_lru_rgn); - rgn->rgn_state = HPB_RGN_INACTIVE; - atomic_dec(&lru_info->active_cnt); -} - -static void ufshpb_purge_active_subregion(struct ufshpb_lu *hpb, - struct ufshpb_subregion *srgn) -{ - if (srgn->srgn_state != HPB_SRGN_UNUSED) { - ufshpb_put_map_ctx(hpb, srgn->mctx); - srgn->srgn_state = HPB_SRGN_UNUSED; - srgn->mctx = NULL; - } -} - -static int ufshpb_issue_umap_req(struct ufshpb_lu *hpb, - struct ufshpb_region *rgn, - bool atomic) -{ - struct ufshpb_req *umap_req; - int rgn_idx = rgn ? rgn->rgn_idx : 0; - - umap_req = ufshpb_get_req(hpb, rgn_idx, REQ_OP_DRV_OUT, atomic); - if (!umap_req) - return -ENOMEM; - - ufshpb_execute_umap_req(hpb, umap_req, rgn); - - return 0; -} - -static int ufshpb_issue_umap_single_req(struct ufshpb_lu *hpb, - struct ufshpb_region *rgn) -{ - return ufshpb_issue_umap_req(hpb, rgn, true); -} - -static void __ufshpb_evict_region(struct ufshpb_lu *hpb, - struct ufshpb_region *rgn) -{ - struct victim_select_info *lru_info; - struct ufshpb_subregion *srgn; - int srgn_idx; - - lru_info = &hpb->lru_info; - - dev_dbg(&hpb->sdev_ufs_lu->sdev_dev, "evict region %d\n", rgn->rgn_idx); - - ufshpb_cleanup_lru_info(lru_info, rgn); - - for_each_sub_region(rgn, srgn_idx, srgn) - ufshpb_purge_active_subregion(hpb, srgn); -} - -static int ufshpb_evict_region(struct ufshpb_lu *hpb, struct ufshpb_region *rgn) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&hpb->rgn_state_lock, flags); - if (rgn->rgn_state == HPB_RGN_PINNED) { - dev_warn(&hpb->sdev_ufs_lu->sdev_dev, - "pinned region cannot drop-out. region %d\n", - rgn->rgn_idx); - goto out; - } - - if (!list_empty(&rgn->list_lru_rgn)) { - if (ufshpb_check_srgns_issue_state(hpb, rgn)) { - ret = -EBUSY; - goto out; - } - - if (hpb->is_hcm) { - spin_unlock_irqrestore(&hpb->rgn_state_lock, flags); - ret = ufshpb_issue_umap_single_req(hpb, rgn); - spin_lock_irqsave(&hpb->rgn_state_lock, flags); - if (ret) - goto out; - } - - __ufshpb_evict_region(hpb, rgn); - } -out: - spin_unlock_irqrestore(&hpb->rgn_state_lock, flags); - return ret; -} - -static int ufshpb_issue_map_req(struct ufshpb_lu *hpb, - struct ufshpb_region *rgn, - struct ufshpb_subregion *srgn) -{ - struct ufshpb_req *map_req; - unsigned long flags; - int ret; - int err = -EAGAIN; - bool alloc_required = false; - enum HPB_SRGN_STATE state = HPB_SRGN_INVALID; - - spin_lock_irqsave(&hpb->rgn_state_lock, flags); - - if (ufshpb_get_state(hpb) != HPB_PRESENT) { - dev_notice(&hpb->sdev_ufs_lu->sdev_dev, - "%s: ufshpb state is not PRESENT\n", __func__); - goto unlock_out; - } - - if ((rgn->rgn_state == HPB_RGN_INACTIVE) && - (srgn->srgn_state == HPB_SRGN_INVALID)) { - err = 0; - goto unlock_out; - } - - if (srgn->srgn_state == HPB_SRGN_UNUSED) - alloc_required = true; - - /* - * If the subregion is already ISSUED state, - * a specific event (e.g., GC or wear-leveling, etc.) occurs in - * the device and HPB response for map loading is received. - * In this case, after finishing the HPB_READ_BUFFER, - * the next HPB_READ_BUFFER is performed again to obtain the latest - * map data. - */ - if (srgn->srgn_state == HPB_SRGN_ISSUED) - goto unlock_out; - - srgn->srgn_state = HPB_SRGN_ISSUED; - spin_unlock_irqrestore(&hpb->rgn_state_lock, flags); - - if (alloc_required) { - srgn->mctx = ufshpb_get_map_ctx(hpb, srgn->is_last); - if (!srgn->mctx) { - dev_err(&hpb->sdev_ufs_lu->sdev_dev, - "get map_ctx failed. region %d - %d\n", - rgn->rgn_idx, srgn->srgn_idx); - state = HPB_SRGN_UNUSED; - goto change_srgn_state; - } - } - - map_req = ufshpb_get_map_req(hpb, srgn); - if (!map_req) - goto change_srgn_state; - - - ret = ufshpb_execute_map_req(hpb, map_req, srgn->is_last); - if (ret) { - dev_err(&hpb->sdev_ufs_lu->sdev_dev, - "%s: issue map_req failed: %d, region %d - %d\n", - __func__, ret, srgn->rgn_idx, srgn->srgn_idx); - goto free_map_req; - } - return 0; - -free_map_req: - ufshpb_put_map_req(hpb, map_req); -change_srgn_state: - spin_lock_irqsave(&hpb->rgn_state_lock, flags); - srgn->srgn_state = state; -unlock_out: - spin_unlock_irqrestore(&hpb->rgn_state_lock, flags); - return err; -} - -static int ufshpb_add_region(struct ufshpb_lu *hpb, struct ufshpb_region *rgn) -{ - struct ufshpb_region *victim_rgn = NULL; - struct victim_select_info *lru_info = &hpb->lru_info; - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&hpb->rgn_state_lock, flags); - /* - * If region belongs to lru_list, just move the region - * to the front of lru list because the state of the region - * is already active-state. - */ - if (!list_empty(&rgn->list_lru_rgn)) { - ufshpb_hit_lru_info(lru_info, rgn); - goto out; - } - - if (rgn->rgn_state == HPB_RGN_INACTIVE) { - if (atomic_read(&lru_info->active_cnt) == - lru_info->max_lru_active_cnt) { - /* - * If the maximum number of active regions - * is exceeded, evict the least recently used region. - * This case may occur when the device responds - * to the eviction information late. - * It is okay to evict the least recently used region, - * because the device could detect this region - * by not issuing HPB_READ - * - * in host control mode, verify that the entering - * region has enough reads - */ - if (hpb->is_hcm && - rgn->reads < hpb->params.eviction_thld_enter) { - ret = -EACCES; - goto out; - } - - victim_rgn = ufshpb_victim_lru_info(hpb); - if (!victim_rgn) { - dev_warn(&hpb->sdev_ufs_lu->sdev_dev, - "cannot get victim region %s\n", - hpb->is_hcm ? "" : "error"); - ret = -ENOMEM; - goto out; - } - - dev_dbg(&hpb->sdev_ufs_lu->sdev_dev, - "LRU full (%d), choose victim %d\n", - atomic_read(&lru_info->active_cnt), - victim_rgn->rgn_idx); - - if (hpb->is_hcm) { - spin_unlock_irqrestore(&hpb->rgn_state_lock, - flags); - ret = ufshpb_issue_umap_single_req(hpb, - victim_rgn); - spin_lock_irqsave(&hpb->rgn_state_lock, - flags); - if (ret) - goto out; - } - - __ufshpb_evict_region(hpb, victim_rgn); - } - - /* - * When a region is added to lru_info list_head, - * it is guaranteed that the subregion has been - * assigned all mctx. If failed, try to receive mctx again - * without being added to lru_info list_head - */ - ufshpb_add_lru_info(lru_info, rgn); - } -out: - spin_unlock_irqrestore(&hpb->rgn_state_lock, flags); - return ret; -} -/** - *ufshpb_submit_region_inactive() - submit a region to be inactivated later - *@hpb: per-LU HPB instance - *@region_index: the index associated with the region that will be inactivated later - */ -static void ufshpb_submit_region_inactive(struct ufshpb_lu *hpb, int region_index) -{ - int subregion_index; - struct ufshpb_region *rgn; - struct ufshpb_subregion *srgn; - - /* - * Remove this region from active region list and add it to inactive list - */ - spin_lock(&hpb->rsp_list_lock); - ufshpb_update_inactive_info(hpb, region_index); - spin_unlock(&hpb->rsp_list_lock); - - rgn = hpb->rgn_tbl + region_index; - - /* - * Set subregion state to be HPB_SRGN_INVALID, there will no HPB read on this subregion - */ - spin_lock(&hpb->rgn_state_lock); - if (rgn->rgn_state != HPB_RGN_INACTIVE) { - for (subregion_index = 0; subregion_index < rgn->srgn_cnt; subregion_index++) { - srgn = rgn->srgn_tbl + subregion_index; - if (srgn->srgn_state == HPB_SRGN_VALID) - srgn->srgn_state = HPB_SRGN_INVALID; - } - } - spin_unlock(&hpb->rgn_state_lock); -} - -static void ufshpb_rsp_req_region_update(struct ufshpb_lu *hpb, - struct utp_hpb_rsp *rsp_field) -{ - struct ufshpb_region *rgn; - struct ufshpb_subregion *srgn; - int i, rgn_i, srgn_i; - - BUILD_BUG_ON(sizeof(struct ufshpb_active_field) != HPB_ACT_FIELD_SIZE); - /* - * If the active region and the inactive region are the same, - * we will inactivate this region. - * The device could check this (region inactivated) and - * will response the proper active region information - */ - for (i = 0; i < rsp_field->active_rgn_cnt; i++) { - rgn_i = - be16_to_cpu(rsp_field->hpb_active_field[i].active_rgn); - srgn_i = - be16_to_cpu(rsp_field->hpb_active_field[i].active_srgn); - - rgn = hpb->rgn_tbl + rgn_i; - if (hpb->is_hcm && - (rgn->rgn_state != HPB_RGN_ACTIVE || is_rgn_dirty(rgn))) { - /* - * in host control mode, subregion activation - * recommendations are only allowed to active regions. - * Also, ignore recommendations for dirty regions - the - * host will make decisions concerning those by himself - */ - continue; - } - - dev_dbg(&hpb->sdev_ufs_lu->sdev_dev, - "activate(%d) region %d - %d\n", i, rgn_i, srgn_i); - - spin_lock(&hpb->rsp_list_lock); - ufshpb_update_active_info(hpb, rgn_i, srgn_i); - spin_unlock(&hpb->rsp_list_lock); - - srgn = rgn->srgn_tbl + srgn_i; - - /* blocking HPB_READ */ - spin_lock(&hpb->rgn_state_lock); - if (srgn->srgn_state == HPB_SRGN_VALID) - srgn->srgn_state = HPB_SRGN_INVALID; - spin_unlock(&hpb->rgn_state_lock); - } - - if (hpb->is_hcm) { - /* - * in host control mode the device is not allowed to inactivate - * regions - */ - goto out; - } - - for (i = 0; i < rsp_field->inactive_rgn_cnt; i++) { - rgn_i = be16_to_cpu(rsp_field->hpb_inactive_field[i]); - dev_dbg(&hpb->sdev_ufs_lu->sdev_dev, "inactivate(%d) region %d\n", i, rgn_i); - ufshpb_submit_region_inactive(hpb, rgn_i); - } - -out: - dev_dbg(&hpb->sdev_ufs_lu->sdev_dev, "Noti: #ACT %u #INACT %u\n", - rsp_field->active_rgn_cnt, rsp_field->inactive_rgn_cnt); - - if (ufshpb_get_state(hpb) == HPB_PRESENT) - queue_work(ufshpb_wq, &hpb->map_work); -} - -/* - * Set the flags of all active regions to RGN_FLAG_UPDATE to let host side reload L2P entries later - */ -static void ufshpb_set_regions_update(struct ufshpb_lu *hpb) -{ - struct victim_select_info *lru_info = &hpb->lru_info; - struct ufshpb_region *rgn; - unsigned long flags; - - spin_lock_irqsave(&hpb->rgn_state_lock, flags); - - list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn) - set_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags); - - spin_unlock_irqrestore(&hpb->rgn_state_lock, flags); -} - -static void ufshpb_dev_reset_handler(struct ufs_hba *hba) -{ - struct scsi_device *sdev; - struct ufshpb_lu *hpb; - - __shost_for_each_device(sdev, hba->host) { - hpb = ufshpb_get_hpb_data(sdev); - if (!hpb) - continue; - - if (hpb->is_hcm) { - /* - * For the HPB host control mode, in case device powered up and lost HPB - * information, we will set the region flag to be RGN_FLAG_UPDATE, it will - * let host reload its L2P entries(reactivate region in the UFS device). - */ - ufshpb_set_regions_update(hpb); - } else { - /* - * For the HPB device control mode, if host side receives 02h:HPB Operation - * in UPIU response, which means device recommends the host side should - * inactivate all active regions. Here we add all active regions to inactive - * list, they will be inactivated later in ufshpb_map_work_handler(). - */ - struct victim_select_info *lru_info = &hpb->lru_info; - struct ufshpb_region *rgn; - - list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn) - ufshpb_submit_region_inactive(hpb, rgn->rgn_idx); - - if (ufshpb_get_state(hpb) == HPB_PRESENT) - queue_work(ufshpb_wq, &hpb->map_work); - } - } -} - -/* - * This function will parse recommended active subregion information in sense - * data field of response UPIU with SAM_STAT_GOOD state. - */ -void ufshpb_rsp_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) -{ - struct ufshpb_lu *hpb = ufshpb_get_hpb_data(lrbp->cmd->device); - struct utp_hpb_rsp *rsp_field = &lrbp->ucd_rsp_ptr->hr; - int data_seg_len; - - data_seg_len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) - & MASK_RSP_UPIU_DATA_SEG_LEN; - - /* If data segment length is zero, rsp_field is not valid */ - if (!data_seg_len) - return; - - if (unlikely(lrbp->lun != rsp_field->lun)) { - struct scsi_device *sdev; - bool found = false; - - __shost_for_each_device(sdev, hba->host) { - hpb = ufshpb_get_hpb_data(sdev); - - if (!hpb) - continue; - - if (rsp_field->lun == hpb->lun) { - found = true; - break; - } - } - - if (!found) - return; - } - - if (!hpb) - return; - - if (ufshpb_get_state(hpb) == HPB_INIT) - return; - - if ((ufshpb_get_state(hpb) != HPB_PRESENT) && - (ufshpb_get_state(hpb) != HPB_SUSPEND)) { - dev_notice(&hpb->sdev_ufs_lu->sdev_dev, - "%s: ufshpb state is not PRESENT/SUSPEND\n", - __func__); - return; - } - - BUILD_BUG_ON(sizeof(struct utp_hpb_rsp) != UTP_HPB_RSP_SIZE); - - if (!ufshpb_is_hpb_rsp_valid(hba, lrbp, rsp_field)) - return; - - hpb->stats.rcmd_noti_cnt++; - - switch (rsp_field->hpb_op) { - case HPB_RSP_REQ_REGION_UPDATE: - if (data_seg_len != DEV_DATA_SEG_LEN) - dev_warn(&hpb->sdev_ufs_lu->sdev_dev, - "%s: data seg length is not same.\n", - __func__); - ufshpb_rsp_req_region_update(hpb, rsp_field); - break; - case HPB_RSP_DEV_RESET: - dev_warn(&hpb->sdev_ufs_lu->sdev_dev, - "UFS device lost HPB information during PM.\n"); - ufshpb_dev_reset_handler(hba); - - break; - default: - dev_notice(&hpb->sdev_ufs_lu->sdev_dev, - "hpb_op is not available: %d\n", - rsp_field->hpb_op); - break; - } -} - -static void ufshpb_add_active_list(struct ufshpb_lu *hpb, - struct ufshpb_region *rgn, - struct ufshpb_subregion *srgn) -{ - if (!list_empty(&rgn->list_inact_rgn)) - return; - - if (!list_empty(&srgn->list_act_srgn)) { - list_move(&srgn->list_act_srgn, &hpb->lh_act_srgn); - return; - } - - list_add(&srgn->list_act_srgn, &hpb->lh_act_srgn); -} - -static void ufshpb_add_pending_evict_list(struct ufshpb_lu *hpb, - struct ufshpb_region *rgn, - struct list_head *pending_list) -{ - struct ufshpb_subregion *srgn; - int srgn_idx; - - if (!list_empty(&rgn->list_inact_rgn)) - return; - - for_each_sub_region(rgn, srgn_idx, srgn) - if (!list_empty(&srgn->list_act_srgn)) - return; - - list_add_tail(&rgn->list_inact_rgn, pending_list); -} - -static void ufshpb_run_active_subregion_list(struct ufshpb_lu *hpb) -{ - struct ufshpb_region *rgn; - struct ufshpb_subregion *srgn; - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&hpb->rsp_list_lock, flags); - while ((srgn = list_first_entry_or_null(&hpb->lh_act_srgn, - struct ufshpb_subregion, - list_act_srgn))) { - if (ufshpb_get_state(hpb) == HPB_SUSPEND) - break; - - list_del_init(&srgn->list_act_srgn); - spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); - - rgn = hpb->rgn_tbl + srgn->rgn_idx; - ret = ufshpb_add_region(hpb, rgn); - if (ret) - goto active_failed; - - ret = ufshpb_issue_map_req(hpb, rgn, srgn); - if (ret) { - dev_err(&hpb->sdev_ufs_lu->sdev_dev, - "issue map_req failed. ret %d, region %d - %d\n", - ret, rgn->rgn_idx, srgn->srgn_idx); - goto active_failed; - } - spin_lock_irqsave(&hpb->rsp_list_lock, flags); - } - spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); - return; - -active_failed: - dev_err(&hpb->sdev_ufs_lu->sdev_dev, "failed to activate region %d - %d, will retry\n", - rgn->rgn_idx, srgn->srgn_idx); - spin_lock_irqsave(&hpb->rsp_list_lock, flags); - ufshpb_add_active_list(hpb, rgn, srgn); - spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); -} - -static void ufshpb_run_inactive_region_list(struct ufshpb_lu *hpb) -{ - struct ufshpb_region *rgn; - unsigned long flags; - int ret; - LIST_HEAD(pending_list); - - spin_lock_irqsave(&hpb->rsp_list_lock, flags); - while ((rgn = list_first_entry_or_null(&hpb->lh_inact_rgn, - struct ufshpb_region, - list_inact_rgn))) { - if (ufshpb_get_state(hpb) == HPB_SUSPEND) - break; - - list_del_init(&rgn->list_inact_rgn); - spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); - - ret = ufshpb_evict_region(hpb, rgn); - if (ret) { - spin_lock_irqsave(&hpb->rsp_list_lock, flags); - ufshpb_add_pending_evict_list(hpb, rgn, &pending_list); - spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); - } - - spin_lock_irqsave(&hpb->rsp_list_lock, flags); - } - - list_splice(&pending_list, &hpb->lh_inact_rgn); - spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); -} - -static void ufshpb_normalization_work_handler(struct work_struct *work) -{ - struct ufshpb_lu *hpb = container_of(work, struct ufshpb_lu, - ufshpb_normalization_work); - int rgn_idx; - u8 factor = hpb->params.normalization_factor; - - for (rgn_idx = 0; rgn_idx < hpb->rgns_per_lu; rgn_idx++) { - struct ufshpb_region *rgn = hpb->rgn_tbl + rgn_idx; - int srgn_idx; - - spin_lock(&rgn->rgn_lock); - rgn->reads = 0; - for (srgn_idx = 0; srgn_idx < hpb->srgns_per_rgn; srgn_idx++) { - struct ufshpb_subregion *srgn = rgn->srgn_tbl + srgn_idx; - - srgn->reads >>= factor; - rgn->reads += srgn->reads; - } - spin_unlock(&rgn->rgn_lock); - - if (rgn->rgn_state != HPB_RGN_ACTIVE || rgn->reads) - continue; - - /* if region is active but has no reads - inactivate it */ - spin_lock(&hpb->rsp_list_lock); - ufshpb_update_inactive_info(hpb, rgn->rgn_idx); - spin_unlock(&hpb->rsp_list_lock); - } -} - -static void ufshpb_map_work_handler(struct work_struct *work) -{ - struct ufshpb_lu *hpb = container_of(work, struct ufshpb_lu, map_work); - - if (ufshpb_get_state(hpb) != HPB_PRESENT) { - dev_notice(&hpb->sdev_ufs_lu->sdev_dev, - "%s: ufshpb state is not PRESENT\n", __func__); - return; - } - - ufshpb_run_inactive_region_list(hpb); - ufshpb_run_active_subregion_list(hpb); -} - -/* - * this function doesn't need to hold lock due to be called in init. - * (rgn_state_lock, rsp_list_lock, etc..) - */ -static int ufshpb_init_pinned_active_region(struct ufs_hba *hba, - struct ufshpb_lu *hpb, - struct ufshpb_region *rgn) -{ - struct ufshpb_subregion *srgn; - int srgn_idx, i; - int err = 0; - - for_each_sub_region(rgn, srgn_idx, srgn) { - srgn->mctx = ufshpb_get_map_ctx(hpb, srgn->is_last); - srgn->srgn_state = HPB_SRGN_INVALID; - if (!srgn->mctx) { - err = -ENOMEM; - dev_err(hba->dev, - "alloc mctx for pinned region failed\n"); - goto release; - } - - list_add_tail(&srgn->list_act_srgn, &hpb->lh_act_srgn); - } - - rgn->rgn_state = HPB_RGN_PINNED; - return 0; - -release: - for (i = 0; i < srgn_idx; i++) { - srgn = rgn->srgn_tbl + i; - ufshpb_put_map_ctx(hpb, srgn->mctx); - } - return err; -} - -static void ufshpb_init_subregion_tbl(struct ufshpb_lu *hpb, - struct ufshpb_region *rgn, bool last) -{ - int srgn_idx; - struct ufshpb_subregion *srgn; - - for_each_sub_region(rgn, srgn_idx, srgn) { - INIT_LIST_HEAD(&srgn->list_act_srgn); - - srgn->rgn_idx = rgn->rgn_idx; - srgn->srgn_idx = srgn_idx; - srgn->srgn_state = HPB_SRGN_UNUSED; - } - - if (unlikely(last && hpb->last_srgn_entries)) - srgn->is_last = true; -} - -static int ufshpb_alloc_subregion_tbl(struct ufshpb_lu *hpb, - struct ufshpb_region *rgn, int srgn_cnt) -{ - rgn->srgn_tbl = kvcalloc(srgn_cnt, sizeof(struct ufshpb_subregion), - GFP_KERNEL); - if (!rgn->srgn_tbl) - return -ENOMEM; - - rgn->srgn_cnt = srgn_cnt; - return 0; -} - -static void ufshpb_lu_parameter_init(struct ufs_hba *hba, - struct ufshpb_lu *hpb, - struct ufshpb_dev_info *hpb_dev_info, - struct ufshpb_lu_info *hpb_lu_info) -{ - u32 entries_per_rgn; - u64 rgn_mem_size, tmp; - - if (ufshpb_is_legacy(hba)) - hpb->pre_req_max_tr_len = HPB_LEGACY_CHUNK_HIGH; - else - hpb->pre_req_max_tr_len = hpb_dev_info->max_hpb_single_cmd; - - hpb->lu_pinned_start = hpb_lu_info->pinned_start; - hpb->lu_pinned_end = hpb_lu_info->num_pinned ? - (hpb_lu_info->pinned_start + hpb_lu_info->num_pinned - 1) - : PINNED_NOT_SET; - hpb->lru_info.max_lru_active_cnt = - hpb_lu_info->max_active_rgns - hpb_lu_info->num_pinned; - - rgn_mem_size = (1ULL << hpb_dev_info->rgn_size) * HPB_RGN_SIZE_UNIT - * HPB_ENTRY_SIZE; - do_div(rgn_mem_size, HPB_ENTRY_BLOCK_SIZE); - hpb->srgn_mem_size = (1ULL << hpb_dev_info->srgn_size) - * HPB_RGN_SIZE_UNIT / HPB_ENTRY_BLOCK_SIZE * HPB_ENTRY_SIZE; - - tmp = rgn_mem_size; - do_div(tmp, HPB_ENTRY_SIZE); - entries_per_rgn = (u32)tmp; - hpb->entries_per_rgn_shift = ilog2(entries_per_rgn); - hpb->entries_per_rgn_mask = entries_per_rgn - 1; - - hpb->entries_per_srgn = hpb->srgn_mem_size / HPB_ENTRY_SIZE; - hpb->entries_per_srgn_shift = ilog2(hpb->entries_per_srgn); - hpb->entries_per_srgn_mask = hpb->entries_per_srgn - 1; - - tmp = rgn_mem_size; - do_div(tmp, hpb->srgn_mem_size); - hpb->srgns_per_rgn = (int)tmp; - - hpb->rgns_per_lu = DIV_ROUND_UP(hpb_lu_info->num_blocks, - entries_per_rgn); - hpb->srgns_per_lu = DIV_ROUND_UP(hpb_lu_info->num_blocks, - (hpb->srgn_mem_size / HPB_ENTRY_SIZE)); - hpb->last_srgn_entries = hpb_lu_info->num_blocks - % (hpb->srgn_mem_size / HPB_ENTRY_SIZE); - - hpb->pages_per_srgn = DIV_ROUND_UP(hpb->srgn_mem_size, PAGE_SIZE); - - if (hpb_dev_info->control_mode == HPB_HOST_CONTROL) - hpb->is_hcm = true; -} - -static int ufshpb_alloc_region_tbl(struct ufs_hba *hba, struct ufshpb_lu *hpb) -{ - struct ufshpb_region *rgn_table, *rgn; - int rgn_idx, i; - int ret = 0; - - rgn_table = kvcalloc(hpb->rgns_per_lu, sizeof(struct ufshpb_region), - GFP_KERNEL); - if (!rgn_table) - return -ENOMEM; - - for (rgn_idx = 0; rgn_idx < hpb->rgns_per_lu; rgn_idx++) { - int srgn_cnt = hpb->srgns_per_rgn; - bool last_srgn = false; - - rgn = rgn_table + rgn_idx; - rgn->rgn_idx = rgn_idx; - - spin_lock_init(&rgn->rgn_lock); - - INIT_LIST_HEAD(&rgn->list_inact_rgn); - INIT_LIST_HEAD(&rgn->list_lru_rgn); - INIT_LIST_HEAD(&rgn->list_expired_rgn); - - if (rgn_idx == hpb->rgns_per_lu - 1) { - srgn_cnt = ((hpb->srgns_per_lu - 1) % - hpb->srgns_per_rgn) + 1; - last_srgn = true; - } - - ret = ufshpb_alloc_subregion_tbl(hpb, rgn, srgn_cnt); - if (ret) - goto release_srgn_table; - ufshpb_init_subregion_tbl(hpb, rgn, last_srgn); - - if (ufshpb_is_pinned_region(hpb, rgn_idx)) { - ret = ufshpb_init_pinned_active_region(hba, hpb, rgn); - if (ret) - goto release_srgn_table; - } else { - rgn->rgn_state = HPB_RGN_INACTIVE; - } - - rgn->rgn_flags = 0; - rgn->hpb = hpb; - } - - hpb->rgn_tbl = rgn_table; - - return 0; - -release_srgn_table: - for (i = 0; i <= rgn_idx; i++) - kvfree(rgn_table[i].srgn_tbl); - - kvfree(rgn_table); - return ret; -} - -static void ufshpb_destroy_subregion_tbl(struct ufshpb_lu *hpb, - struct ufshpb_region *rgn) -{ - int srgn_idx; - struct ufshpb_subregion *srgn; - - for_each_sub_region(rgn, srgn_idx, srgn) - if (srgn->srgn_state != HPB_SRGN_UNUSED) { - srgn->srgn_state = HPB_SRGN_UNUSED; - ufshpb_put_map_ctx(hpb, srgn->mctx); - } -} - -static void ufshpb_destroy_region_tbl(struct ufshpb_lu *hpb) -{ - int rgn_idx; - - for (rgn_idx = 0; rgn_idx < hpb->rgns_per_lu; rgn_idx++) { - struct ufshpb_region *rgn; - - rgn = hpb->rgn_tbl + rgn_idx; - if (rgn->rgn_state != HPB_RGN_INACTIVE) { - rgn->rgn_state = HPB_RGN_INACTIVE; - - ufshpb_destroy_subregion_tbl(hpb, rgn); - } - - kvfree(rgn->srgn_tbl); - } - - kvfree(hpb->rgn_tbl); -} - -/* SYSFS functions */ -#define ufshpb_sysfs_attr_show_func(__name) \ -static ssize_t __name##_show(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct scsi_device *sdev = to_scsi_device(dev); \ - struct ufshpb_lu *hpb = ufshpb_get_hpb_data(sdev); \ - \ - if (!hpb) \ - return -ENODEV; \ - \ - return sysfs_emit(buf, "%llu\n", hpb->stats.__name); \ -} \ -\ -static DEVICE_ATTR_RO(__name) - -ufshpb_sysfs_attr_show_func(hit_cnt); -ufshpb_sysfs_attr_show_func(miss_cnt); -ufshpb_sysfs_attr_show_func(rcmd_noti_cnt); -ufshpb_sysfs_attr_show_func(rcmd_active_cnt); -ufshpb_sysfs_attr_show_func(rcmd_inactive_cnt); -ufshpb_sysfs_attr_show_func(map_req_cnt); -ufshpb_sysfs_attr_show_func(umap_req_cnt); - -static struct attribute *hpb_dev_stat_attrs[] = { - &dev_attr_hit_cnt.attr, - &dev_attr_miss_cnt.attr, - &dev_attr_rcmd_noti_cnt.attr, - &dev_attr_rcmd_active_cnt.attr, - &dev_attr_rcmd_inactive_cnt.attr, - &dev_attr_map_req_cnt.attr, - &dev_attr_umap_req_cnt.attr, - NULL, -}; - -struct attribute_group ufs_sysfs_hpb_stat_group = { - .name = "hpb_stats", - .attrs = hpb_dev_stat_attrs, -}; - -/* SYSFS functions */ -#define ufshpb_sysfs_param_show_func(__name) \ -static ssize_t __name##_show(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct scsi_device *sdev = to_scsi_device(dev); \ - struct ufshpb_lu *hpb = ufshpb_get_hpb_data(sdev); \ - \ - if (!hpb) \ - return -ENODEV; \ - \ - return sysfs_emit(buf, "%d\n", hpb->params.__name); \ -} - -ufshpb_sysfs_param_show_func(requeue_timeout_ms); -static ssize_t -requeue_timeout_ms_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct ufshpb_lu *hpb = ufshpb_get_hpb_data(sdev); - int val; - - if (!hpb) - return -ENODEV; - - if (kstrtouint(buf, 0, &val)) - return -EINVAL; - - if (val < 0) - return -EINVAL; - - hpb->params.requeue_timeout_ms = val; - - return count; -} -static DEVICE_ATTR_RW(requeue_timeout_ms); - -ufshpb_sysfs_param_show_func(activation_thld); -static ssize_t -activation_thld_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct ufshpb_lu *hpb = ufshpb_get_hpb_data(sdev); - int val; - - if (!hpb) - return -ENODEV; - - if (!hpb->is_hcm) - return -EOPNOTSUPP; - - if (kstrtouint(buf, 0, &val)) - return -EINVAL; - - if (val <= 0) - return -EINVAL; - - hpb->params.activation_thld = val; - - return count; -} -static DEVICE_ATTR_RW(activation_thld); - -ufshpb_sysfs_param_show_func(normalization_factor); -static ssize_t -normalization_factor_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct ufshpb_lu *hpb = ufshpb_get_hpb_data(sdev); - int val; - - if (!hpb) - return -ENODEV; - - if (!hpb->is_hcm) - return -EOPNOTSUPP; - - if (kstrtouint(buf, 0, &val)) - return -EINVAL; - - if (val <= 0 || val > ilog2(hpb->entries_per_srgn)) - return -EINVAL; - - hpb->params.normalization_factor = val; - - return count; -} -static DEVICE_ATTR_RW(normalization_factor); - -ufshpb_sysfs_param_show_func(eviction_thld_enter); -static ssize_t -eviction_thld_enter_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct ufshpb_lu *hpb = ufshpb_get_hpb_data(sdev); - int val; - - if (!hpb) - return -ENODEV; - - if (!hpb->is_hcm) - return -EOPNOTSUPP; - - if (kstrtouint(buf, 0, &val)) - return -EINVAL; - - if (val <= hpb->params.eviction_thld_exit) - return -EINVAL; - - hpb->params.eviction_thld_enter = val; - - return count; -} -static DEVICE_ATTR_RW(eviction_thld_enter); - -ufshpb_sysfs_param_show_func(eviction_thld_exit); -static ssize_t -eviction_thld_exit_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct ufshpb_lu *hpb = ufshpb_get_hpb_data(sdev); - int val; - - if (!hpb) - return -ENODEV; - - if (!hpb->is_hcm) - return -EOPNOTSUPP; - - if (kstrtouint(buf, 0, &val)) - return -EINVAL; - - if (val <= hpb->params.activation_thld) - return -EINVAL; - - hpb->params.eviction_thld_exit = val; - - return count; -} -static DEVICE_ATTR_RW(eviction_thld_exit); - -ufshpb_sysfs_param_show_func(read_timeout_ms); -static ssize_t -read_timeout_ms_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct ufshpb_lu *hpb = ufshpb_get_hpb_data(sdev); - int val; - - if (!hpb) - return -ENODEV; - - if (!hpb->is_hcm) - return -EOPNOTSUPP; - - if (kstrtouint(buf, 0, &val)) - return -EINVAL; - - /* read_timeout >> timeout_polling_interval */ - if (val < hpb->params.timeout_polling_interval_ms * 2) - return -EINVAL; - - hpb->params.read_timeout_ms = val; - - return count; -} -static DEVICE_ATTR_RW(read_timeout_ms); - -ufshpb_sysfs_param_show_func(read_timeout_expiries); -static ssize_t -read_timeout_expiries_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct ufshpb_lu *hpb = ufshpb_get_hpb_data(sdev); - int val; - - if (!hpb) - return -ENODEV; - - if (!hpb->is_hcm) - return -EOPNOTSUPP; - - if (kstrtouint(buf, 0, &val)) - return -EINVAL; - - if (val <= 0) - return -EINVAL; - - hpb->params.read_timeout_expiries = val; - - return count; -} -static DEVICE_ATTR_RW(read_timeout_expiries); - -ufshpb_sysfs_param_show_func(timeout_polling_interval_ms); -static ssize_t -timeout_polling_interval_ms_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct ufshpb_lu *hpb = ufshpb_get_hpb_data(sdev); - int val; - - if (!hpb) - return -ENODEV; - - if (!hpb->is_hcm) - return -EOPNOTSUPP; - - if (kstrtouint(buf, 0, &val)) - return -EINVAL; - - /* timeout_polling_interval << read_timeout */ - if (val <= 0 || val > hpb->params.read_timeout_ms / 2) - return -EINVAL; - - hpb->params.timeout_polling_interval_ms = val; - - return count; -} -static DEVICE_ATTR_RW(timeout_polling_interval_ms); - -ufshpb_sysfs_param_show_func(inflight_map_req); -static ssize_t inflight_map_req_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct ufshpb_lu *hpb = ufshpb_get_hpb_data(sdev); - int val; - - if (!hpb) - return -ENODEV; - - if (!hpb->is_hcm) - return -EOPNOTSUPP; - - if (kstrtouint(buf, 0, &val)) - return -EINVAL; - - if (val <= 0 || val > hpb->sdev_ufs_lu->queue_depth - 1) - return -EINVAL; - - hpb->params.inflight_map_req = val; - - return count; -} -static DEVICE_ATTR_RW(inflight_map_req); - -static void ufshpb_hcm_param_init(struct ufshpb_lu *hpb) -{ - hpb->params.activation_thld = ACTIVATION_THRESHOLD; - hpb->params.normalization_factor = 1; - hpb->params.eviction_thld_enter = (ACTIVATION_THRESHOLD << 5); - hpb->params.eviction_thld_exit = (ACTIVATION_THRESHOLD << 4); - hpb->params.read_timeout_ms = READ_TO_MS; - hpb->params.read_timeout_expiries = READ_TO_EXPIRIES; - hpb->params.timeout_polling_interval_ms = POLLING_INTERVAL_MS; - hpb->params.inflight_map_req = THROTTLE_MAP_REQ_DEFAULT; -} - -static struct attribute *hpb_dev_param_attrs[] = { - &dev_attr_requeue_timeout_ms.attr, - &dev_attr_activation_thld.attr, - &dev_attr_normalization_factor.attr, - &dev_attr_eviction_thld_enter.attr, - &dev_attr_eviction_thld_exit.attr, - &dev_attr_read_timeout_ms.attr, - &dev_attr_read_timeout_expiries.attr, - &dev_attr_timeout_polling_interval_ms.attr, - &dev_attr_inflight_map_req.attr, - NULL, -}; - -struct attribute_group ufs_sysfs_hpb_param_group = { - .name = "hpb_params", - .attrs = hpb_dev_param_attrs, -}; - -static int ufshpb_pre_req_mempool_init(struct ufshpb_lu *hpb) -{ - struct ufshpb_req *pre_req = NULL, *t; - int qd = hpb->sdev_ufs_lu->queue_depth / 2; - int i; - - INIT_LIST_HEAD(&hpb->lh_pre_req_free); - - hpb->pre_req = kcalloc(qd, sizeof(struct ufshpb_req), GFP_KERNEL); - hpb->throttle_pre_req = qd; - hpb->num_inflight_pre_req = 0; - - if (!hpb->pre_req) - goto release_mem; - - for (i = 0; i < qd; i++) { - pre_req = hpb->pre_req + i; - INIT_LIST_HEAD(&pre_req->list_req); - pre_req->req = NULL; - - pre_req->bio = bio_alloc(NULL, 1, 0, GFP_KERNEL); - if (!pre_req->bio) - goto release_mem; - - pre_req->wb.m_page = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (!pre_req->wb.m_page) { - bio_put(pre_req->bio); - goto release_mem; - } - - list_add_tail(&pre_req->list_req, &hpb->lh_pre_req_free); - } - - return 0; -release_mem: - list_for_each_entry_safe(pre_req, t, &hpb->lh_pre_req_free, list_req) { - list_del_init(&pre_req->list_req); - bio_put(pre_req->bio); - __free_page(pre_req->wb.m_page); - } - - kfree(hpb->pre_req); - return -ENOMEM; -} - -static void ufshpb_pre_req_mempool_destroy(struct ufshpb_lu *hpb) -{ - struct ufshpb_req *pre_req = NULL; - int i; - - for (i = 0; i < hpb->throttle_pre_req; i++) { - pre_req = hpb->pre_req + i; - bio_put(hpb->pre_req[i].bio); - if (!pre_req->wb.m_page) - __free_page(hpb->pre_req[i].wb.m_page); - list_del_init(&pre_req->list_req); - } - - kfree(hpb->pre_req); -} - -static void ufshpb_stat_init(struct ufshpb_lu *hpb) -{ - hpb->stats.hit_cnt = 0; - hpb->stats.miss_cnt = 0; - hpb->stats.rcmd_noti_cnt = 0; - hpb->stats.rcmd_active_cnt = 0; - hpb->stats.rcmd_inactive_cnt = 0; - hpb->stats.map_req_cnt = 0; - hpb->stats.umap_req_cnt = 0; -} - -static void ufshpb_param_init(struct ufshpb_lu *hpb) -{ - hpb->params.requeue_timeout_ms = HPB_REQUEUE_TIME_MS; - if (hpb->is_hcm) - ufshpb_hcm_param_init(hpb); -} - -static int ufshpb_lu_hpb_init(struct ufs_hba *hba, struct ufshpb_lu *hpb) -{ - int ret; - - spin_lock_init(&hpb->rgn_state_lock); - spin_lock_init(&hpb->rsp_list_lock); - spin_lock_init(&hpb->param_lock); - - INIT_LIST_HEAD(&hpb->lru_info.lh_lru_rgn); - INIT_LIST_HEAD(&hpb->lh_act_srgn); - INIT_LIST_HEAD(&hpb->lh_inact_rgn); - INIT_LIST_HEAD(&hpb->list_hpb_lu); - - INIT_WORK(&hpb->map_work, ufshpb_map_work_handler); - if (hpb->is_hcm) { - INIT_WORK(&hpb->ufshpb_normalization_work, - ufshpb_normalization_work_handler); - INIT_DELAYED_WORK(&hpb->ufshpb_read_to_work, - ufshpb_read_to_handler); - } - - hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache", - sizeof(struct ufshpb_req), 0, 0, NULL); - if (!hpb->map_req_cache) { - dev_err(hba->dev, "ufshpb(%d) ufshpb_req_cache create fail", - hpb->lun); - return -ENOMEM; - } - - hpb->m_page_cache = kmem_cache_create("ufshpb_m_page_cache", - sizeof(struct page *) * hpb->pages_per_srgn, - 0, 0, NULL); - if (!hpb->m_page_cache) { - dev_err(hba->dev, "ufshpb(%d) ufshpb_m_page_cache create fail", - hpb->lun); - ret = -ENOMEM; - goto release_req_cache; - } - - ret = ufshpb_pre_req_mempool_init(hpb); - if (ret) { - dev_err(hba->dev, "ufshpb(%d) pre_req_mempool init fail", - hpb->lun); - goto release_m_page_cache; - } - - ret = ufshpb_alloc_region_tbl(hba, hpb); - if (ret) - goto release_pre_req_mempool; - - ufshpb_stat_init(hpb); - ufshpb_param_init(hpb); - - if (hpb->is_hcm) { - unsigned int poll; - - poll = hpb->params.timeout_polling_interval_ms; - schedule_delayed_work(&hpb->ufshpb_read_to_work, - msecs_to_jiffies(poll)); - } - - return 0; - -release_pre_req_mempool: - ufshpb_pre_req_mempool_destroy(hpb); -release_m_page_cache: - kmem_cache_destroy(hpb->m_page_cache); -release_req_cache: - kmem_cache_destroy(hpb->map_req_cache); - return ret; -} - -static struct ufshpb_lu * -ufshpb_alloc_hpb_lu(struct ufs_hba *hba, struct scsi_device *sdev, - struct ufshpb_dev_info *hpb_dev_info, - struct ufshpb_lu_info *hpb_lu_info) -{ - struct ufshpb_lu *hpb; - int ret; - - hpb = kzalloc(sizeof(struct ufshpb_lu), GFP_KERNEL); - if (!hpb) - return NULL; - - hpb->lun = sdev->lun; - hpb->sdev_ufs_lu = sdev; - - ufshpb_lu_parameter_init(hba, hpb, hpb_dev_info, hpb_lu_info); - - ret = ufshpb_lu_hpb_init(hba, hpb); - if (ret) { - dev_err(hba->dev, "hpb lu init failed. ret %d", ret); - goto release_hpb; - } - - sdev->hostdata = hpb; - return hpb; - -release_hpb: - kfree(hpb); - return NULL; -} - -static void ufshpb_discard_rsp_lists(struct ufshpb_lu *hpb) -{ - struct ufshpb_region *rgn, *next_rgn; - struct ufshpb_subregion *srgn, *next_srgn; - unsigned long flags; - - /* - * If the device reset occurred, the remaining HPB region information - * may be stale. Therefore, by discarding the lists of HPB response - * that remained after reset, we prevent unnecessary work. - */ - spin_lock_irqsave(&hpb->rsp_list_lock, flags); - list_for_each_entry_safe(rgn, next_rgn, &hpb->lh_inact_rgn, - list_inact_rgn) - list_del_init(&rgn->list_inact_rgn); - - list_for_each_entry_safe(srgn, next_srgn, &hpb->lh_act_srgn, - list_act_srgn) - list_del_init(&srgn->list_act_srgn); - spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); -} - -static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb) -{ - if (hpb->is_hcm) { - cancel_delayed_work_sync(&hpb->ufshpb_read_to_work); - cancel_work_sync(&hpb->ufshpb_normalization_work); - } - cancel_work_sync(&hpb->map_work); -} - -static bool ufshpb_check_hpb_reset_query(struct ufs_hba *hba) -{ - int err = 0; - bool flag_res = true; - int try; - - /* wait for the device to complete HPB reset query */ - for (try = 0; try < HPB_RESET_REQ_RETRIES; try++) { - dev_dbg(hba->dev, - "%s: start flag reset polling %d times\n", - __func__, try); - - /* Poll fHpbReset flag to be cleared */ - err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG, - QUERY_FLAG_IDN_HPB_RESET, 0, &flag_res); - - if (err) { - dev_err(hba->dev, - "%s: reading fHpbReset flag failed with error %d\n", - __func__, err); - return flag_res; - } - - if (!flag_res) - goto out; - - usleep_range(1000, 1100); - } - if (flag_res) { - dev_err(hba->dev, - "%s: fHpbReset was not cleared by the device\n", - __func__); - } -out: - return flag_res; -} - -/** - * ufshpb_toggle_state - switch HPB state of all LUs - * @hba: per-adapter instance - * @src: expected current HPB state - * @dest: target HPB state to switch to - */ -void ufshpb_toggle_state(struct ufs_hba *hba, enum UFSHPB_STATE src, enum UFSHPB_STATE dest) -{ - struct ufshpb_lu *hpb; - struct scsi_device *sdev; - - shost_for_each_device(sdev, hba->host) { - hpb = ufshpb_get_hpb_data(sdev); - - if (!hpb || ufshpb_get_state(hpb) != src) - continue; - ufshpb_set_state(hpb, dest); - - if (dest == HPB_RESET) { - ufshpb_cancel_jobs(hpb); - ufshpb_discard_rsp_lists(hpb); - } - } -} - -void ufshpb_suspend(struct ufs_hba *hba) -{ - struct ufshpb_lu *hpb; - struct scsi_device *sdev; - - shost_for_each_device(sdev, hba->host) { - hpb = ufshpb_get_hpb_data(sdev); - if (!hpb || ufshpb_get_state(hpb) != HPB_PRESENT) - continue; - - ufshpb_set_state(hpb, HPB_SUSPEND); - ufshpb_cancel_jobs(hpb); - } -} - -void ufshpb_resume(struct ufs_hba *hba) -{ - struct ufshpb_lu *hpb; - struct scsi_device *sdev; - - shost_for_each_device(sdev, hba->host) { - hpb = ufshpb_get_hpb_data(sdev); - if (!hpb || ufshpb_get_state(hpb) != HPB_SUSPEND) - continue; - - ufshpb_set_state(hpb, HPB_PRESENT); - ufshpb_kick_map_work(hpb); - if (hpb->is_hcm) { - unsigned int poll = hpb->params.timeout_polling_interval_ms; - - schedule_delayed_work(&hpb->ufshpb_read_to_work, msecs_to_jiffies(poll)); - } - } -} - -static int ufshpb_get_lu_info(struct ufs_hba *hba, int lun, - struct ufshpb_lu_info *hpb_lu_info) -{ - u16 max_active_rgns; - u8 lu_enable; - int size = QUERY_DESC_MAX_SIZE; - int ret; - char desc_buf[QUERY_DESC_MAX_SIZE]; - - ufshcd_rpm_get_sync(hba); - ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC, - QUERY_DESC_IDN_UNIT, lun, 0, - desc_buf, &size); - ufshcd_rpm_put_sync(hba); - - if (ret) { - dev_err(hba->dev, - "%s: idn: %d lun: %d query request failed", - __func__, QUERY_DESC_IDN_UNIT, lun); - return ret; - } - - lu_enable = desc_buf[UNIT_DESC_PARAM_LU_ENABLE]; - if (lu_enable != LU_ENABLED_HPB_FUNC) - return -ENODEV; - - max_active_rgns = get_unaligned_be16( - desc_buf + UNIT_DESC_PARAM_HPB_LU_MAX_ACTIVE_RGNS); - if (!max_active_rgns) { - dev_err(hba->dev, - "lun %d wrong number of max active regions\n", lun); - return -ENODEV; - } - - hpb_lu_info->num_blocks = get_unaligned_be64( - desc_buf + UNIT_DESC_PARAM_LOGICAL_BLK_COUNT); - hpb_lu_info->pinned_start = get_unaligned_be16( - desc_buf + UNIT_DESC_PARAM_HPB_PIN_RGN_START_OFF); - hpb_lu_info->num_pinned = get_unaligned_be16( - desc_buf + UNIT_DESC_PARAM_HPB_NUM_PIN_RGNS); - hpb_lu_info->max_active_rgns = max_active_rgns; - - return 0; -} - -void ufshpb_destroy_lu(struct ufs_hba *hba, struct scsi_device *sdev) -{ - struct ufshpb_lu *hpb = ufshpb_get_hpb_data(sdev); - - if (!hpb) - return; - - ufshpb_set_state(hpb, HPB_FAILED); - - sdev = hpb->sdev_ufs_lu; - sdev->hostdata = NULL; - - ufshpb_cancel_jobs(hpb); - - ufshpb_pre_req_mempool_destroy(hpb); - ufshpb_destroy_region_tbl(hpb); - - kmem_cache_destroy(hpb->map_req_cache); - kmem_cache_destroy(hpb->m_page_cache); - - list_del_init(&hpb->list_hpb_lu); - - kfree(hpb); -} - -static void ufshpb_hpb_lu_prepared(struct ufs_hba *hba) -{ - int pool_size; - struct ufshpb_lu *hpb; - struct scsi_device *sdev; - bool init_success; - - if (tot_active_srgn_pages == 0) { - ufshpb_remove(hba); - return; - } - - init_success = !ufshpb_check_hpb_reset_query(hba); - - pool_size = PAGE_ALIGN(ufshpb_host_map_kbytes * SZ_1K) / PAGE_SIZE; - if (pool_size > tot_active_srgn_pages) { - mempool_resize(ufshpb_mctx_pool, tot_active_srgn_pages); - mempool_resize(ufshpb_page_pool, tot_active_srgn_pages); - } - - shost_for_each_device(sdev, hba->host) { - hpb = ufshpb_get_hpb_data(sdev); - if (!hpb) - continue; - - if (init_success) { - ufshpb_set_state(hpb, HPB_PRESENT); - if ((hpb->lu_pinned_end - hpb->lu_pinned_start) > 0) - queue_work(ufshpb_wq, &hpb->map_work); - } else { - dev_err(hba->dev, "destroy HPB lu %d\n", hpb->lun); - ufshpb_destroy_lu(hba, sdev); - } - } - - if (!init_success) - ufshpb_remove(hba); -} - -void ufshpb_init_hpb_lu(struct ufs_hba *hba, struct scsi_device *sdev) -{ - struct ufshpb_lu *hpb; - int ret; - struct ufshpb_lu_info hpb_lu_info = { 0 }; - int lun = sdev->lun; - - if (lun >= hba->dev_info.max_lu_supported) - goto out; - - ret = ufshpb_get_lu_info(hba, lun, &hpb_lu_info); - if (ret) - goto out; - - hpb = ufshpb_alloc_hpb_lu(hba, sdev, &hba->ufshpb_dev, - &hpb_lu_info); - if (!hpb) - goto out; - - tot_active_srgn_pages += hpb_lu_info.max_active_rgns * - hpb->srgns_per_rgn * hpb->pages_per_srgn; - -out: - /* All LUs are initialized */ - if (atomic_dec_and_test(&hba->ufshpb_dev.slave_conf_cnt)) - ufshpb_hpb_lu_prepared(hba); -} - -static int ufshpb_init_mem_wq(struct ufs_hba *hba) -{ - int ret; - unsigned int pool_size; - - ufshpb_mctx_cache = kmem_cache_create("ufshpb_mctx_cache", - sizeof(struct ufshpb_map_ctx), - 0, 0, NULL); - if (!ufshpb_mctx_cache) { - dev_err(hba->dev, "ufshpb: cannot init mctx cache\n"); - return -ENOMEM; - } - - pool_size = PAGE_ALIGN(ufshpb_host_map_kbytes * SZ_1K) / PAGE_SIZE; - dev_info(hba->dev, "%s:%d ufshpb_host_map_kbytes %u pool_size %u\n", - __func__, __LINE__, ufshpb_host_map_kbytes, pool_size); - - ufshpb_mctx_pool = mempool_create_slab_pool(pool_size, - ufshpb_mctx_cache); - if (!ufshpb_mctx_pool) { - dev_err(hba->dev, "ufshpb: cannot init mctx pool\n"); - ret = -ENOMEM; - goto release_mctx_cache; - } - - ufshpb_page_pool = mempool_create_page_pool(pool_size, 0); - if (!ufshpb_page_pool) { - dev_err(hba->dev, "ufshpb: cannot init page pool\n"); - ret = -ENOMEM; - goto release_mctx_pool; - } - - ufshpb_wq = alloc_workqueue("ufshpb-wq", - WQ_UNBOUND | WQ_MEM_RECLAIM, 0); - if (!ufshpb_wq) { - dev_err(hba->dev, "ufshpb: alloc workqueue failed\n"); - ret = -ENOMEM; - goto release_page_pool; - } - - return 0; - -release_page_pool: - mempool_destroy(ufshpb_page_pool); -release_mctx_pool: - mempool_destroy(ufshpb_mctx_pool); -release_mctx_cache: - kmem_cache_destroy(ufshpb_mctx_cache); - return ret; -} - -void ufshpb_get_geo_info(struct ufs_hba *hba, u8 *geo_buf) -{ - struct ufshpb_dev_info *hpb_info = &hba->ufshpb_dev; - int max_active_rgns = 0; - int hpb_num_lu; - - hpb_num_lu = geo_buf[GEOMETRY_DESC_PARAM_HPB_NUMBER_LU]; - if (hpb_num_lu == 0) { - dev_err(hba->dev, "No HPB LU supported\n"); - hpb_info->hpb_disabled = true; - return; - } - - hpb_info->rgn_size = geo_buf[GEOMETRY_DESC_PARAM_HPB_REGION_SIZE]; - hpb_info->srgn_size = geo_buf[GEOMETRY_DESC_PARAM_HPB_SUBREGION_SIZE]; - max_active_rgns = get_unaligned_be16(geo_buf + - GEOMETRY_DESC_PARAM_HPB_MAX_ACTIVE_REGS); - - if (hpb_info->rgn_size == 0 || hpb_info->srgn_size == 0 || - max_active_rgns == 0) { - dev_err(hba->dev, "No HPB supported device\n"); - hpb_info->hpb_disabled = true; - return; - } -} - -void ufshpb_get_dev_info(struct ufs_hba *hba, u8 *desc_buf) -{ - struct ufshpb_dev_info *hpb_dev_info = &hba->ufshpb_dev; - int version, ret; - int max_single_cmd; - - hpb_dev_info->control_mode = desc_buf[DEVICE_DESC_PARAM_HPB_CONTROL]; - - version = get_unaligned_be16(desc_buf + DEVICE_DESC_PARAM_HPB_VER); - if ((version != HPB_SUPPORT_VERSION) && - (version != HPB_SUPPORT_LEGACY_VERSION)) { - dev_err(hba->dev, "%s: HPB %x version is not supported.\n", - __func__, version); - hpb_dev_info->hpb_disabled = true; - return; - } - - if (version == HPB_SUPPORT_LEGACY_VERSION) - hpb_dev_info->is_legacy = true; - - /* - * Get the number of user logical unit to check whether all - * scsi_device finish initialization - */ - hpb_dev_info->num_lu = desc_buf[DEVICE_DESC_PARAM_NUM_LU]; - - if (hpb_dev_info->is_legacy) - return; - - ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, - QUERY_ATTR_IDN_MAX_HPB_SINGLE_CMD, 0, 0, &max_single_cmd); - - if (ret) - hpb_dev_info->max_hpb_single_cmd = HPB_LEGACY_CHUNK_HIGH; - else - hpb_dev_info->max_hpb_single_cmd = min(max_single_cmd + 1, HPB_MULTI_CHUNK_HIGH); -} - -void ufshpb_init(struct ufs_hba *hba) -{ - struct ufshpb_dev_info *hpb_dev_info = &hba->ufshpb_dev; - int try; - int ret; - - if (!ufshpb_is_allowed(hba) || !hba->dev_info.hpb_enabled) - return; - - if (ufshpb_init_mem_wq(hba)) { - hpb_dev_info->hpb_disabled = true; - return; - } - - atomic_set(&hpb_dev_info->slave_conf_cnt, hpb_dev_info->num_lu); - tot_active_srgn_pages = 0; - /* issue HPB reset query */ - for (try = 0; try < HPB_RESET_REQ_RETRIES; try++) { - ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_SET_FLAG, - QUERY_FLAG_IDN_HPB_RESET, 0, NULL); - if (!ret) - break; - } -} - -void ufshpb_remove(struct ufs_hba *hba) -{ - mempool_destroy(ufshpb_page_pool); - mempool_destroy(ufshpb_mctx_pool); - kmem_cache_destroy(ufshpb_mctx_cache); - - destroy_workqueue(ufshpb_wq); -} - -module_param(ufshpb_host_map_kbytes, uint, 0644); -MODULE_PARM_DESC(ufshpb_host_map_kbytes, - "ufshpb host mapping memory kilo-bytes for ufshpb memory-pool"); diff --git a/drivers/ufs/core/ufshpb.h b/drivers/ufs/core/ufshpb.h deleted file mode 100644 index b428bbdd27992..0000000000000 --- a/drivers/ufs/core/ufshpb.h +++ /dev/null @@ -1,318 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Universal Flash Storage Host Performance Booster - * - * Copyright (C) 2017-2021 Samsung Electronics Co., Ltd. - * - * Authors: - * Yongmyung Lee - * Jinyoung Choi - */ - -#ifndef _UFSHPB_H_ -#define _UFSHPB_H_ - -/* hpb response UPIU macro */ -#define HPB_RSP_NONE 0x0 -#define HPB_RSP_REQ_REGION_UPDATE 0x1 -#define HPB_RSP_DEV_RESET 0x2 -#define MAX_ACTIVE_NUM 2 -#define MAX_INACTIVE_NUM 2 -#define DEV_DATA_SEG_LEN 0x14 -#define DEV_SENSE_SEG_LEN 0x12 -#define DEV_DES_TYPE 0x80 -#define DEV_ADDITIONAL_LEN 0x10 - -/* hpb map & entries macro */ -#define HPB_RGN_SIZE_UNIT 512 -#define HPB_ENTRY_BLOCK_SIZE SZ_4K -#define HPB_ENTRY_SIZE 0x8 -#define PINNED_NOT_SET U32_MAX - -/* hpb support chunk size */ -#define HPB_LEGACY_CHUNK_HIGH 1 -#define HPB_MULTI_CHUNK_HIGH 255 - -/* hpb vender defined opcode */ -#define UFSHPB_READ 0xF8 -#define UFSHPB_READ_BUFFER 0xF9 -#define UFSHPB_READ_BUFFER_ID 0x01 -#define UFSHPB_WRITE_BUFFER 0xFA -#define UFSHPB_WRITE_BUFFER_INACT_SINGLE_ID 0x01 -#define UFSHPB_WRITE_BUFFER_PREFETCH_ID 0x02 -#define UFSHPB_WRITE_BUFFER_INACT_ALL_ID 0x03 -#define HPB_WRITE_BUFFER_CMD_LENGTH 10 -#define MAX_HPB_READ_ID 0x7F -#define HPB_READ_BUFFER_CMD_LENGTH 10 -#define LU_ENABLED_HPB_FUNC 0x02 - -#define HPB_RESET_REQ_RETRIES 10 -#define HPB_MAP_REQ_RETRIES 5 -#define HPB_REQUEUE_TIME_MS 0 - -#define HPB_SUPPORT_VERSION 0x200 -#define HPB_SUPPORT_LEGACY_VERSION 0x100 - -enum UFSHPB_MODE { - HPB_HOST_CONTROL, - HPB_DEVICE_CONTROL, -}; - -enum UFSHPB_STATE { - HPB_INIT, - HPB_PRESENT, - HPB_SUSPEND, - HPB_FAILED, - HPB_RESET, -}; - -enum HPB_RGN_STATE { - HPB_RGN_INACTIVE, - HPB_RGN_ACTIVE, - /* pinned regions are always active */ - HPB_RGN_PINNED, -}; - -enum HPB_SRGN_STATE { - HPB_SRGN_UNUSED, - HPB_SRGN_INVALID, - HPB_SRGN_VALID, - HPB_SRGN_ISSUED, -}; - -/** - * struct ufshpb_lu_info - UFSHPB logical unit related info - * @num_blocks: the number of logical block - * @pinned_start: the start region number of pinned region - * @num_pinned: the number of pinned regions - * @max_active_rgns: maximum number of active regions - */ -struct ufshpb_lu_info { - int num_blocks; - int pinned_start; - int num_pinned; - int max_active_rgns; -}; - -struct ufshpb_map_ctx { - struct page **m_page; - unsigned long *ppn_dirty; -}; - -struct ufshpb_subregion { - struct ufshpb_map_ctx *mctx; - enum HPB_SRGN_STATE srgn_state; - int rgn_idx; - int srgn_idx; - bool is_last; - - /* subregion reads - for host mode */ - unsigned int reads; - - /* below information is used by rsp_list */ - struct list_head list_act_srgn; -}; - -struct ufshpb_region { - struct ufshpb_lu *hpb; - struct ufshpb_subregion *srgn_tbl; - enum HPB_RGN_STATE rgn_state; - int rgn_idx; - int srgn_cnt; - - /* below information is used by rsp_list */ - struct list_head list_inact_rgn; - - /* below information is used by lru */ - struct list_head list_lru_rgn; - unsigned long rgn_flags; -#define RGN_FLAG_DIRTY 0 -#define RGN_FLAG_UPDATE 1 - - /* region reads - for host mode */ - spinlock_t rgn_lock; - unsigned int reads; - /* region "cold" timer - for host mode */ - ktime_t read_timeout; - unsigned int read_timeout_expiries; - struct list_head list_expired_rgn; -}; - -#define for_each_sub_region(rgn, i, srgn) \ - for ((i) = 0; \ - ((i) < (rgn)->srgn_cnt) && ((srgn) = &(rgn)->srgn_tbl[i]); \ - (i)++) - -/** - * struct ufshpb_req - HPB related request structure (write/read buffer) - * @req: block layer request structure - * @bio: bio for this request - * @hpb: ufshpb_lu structure that related to - * @list_req: ufshpb_req mempool list - * @sense: store its sense data - * @mctx: L2P map information - * @rgn_idx: target region index - * @srgn_idx: target sub-region index - * @lun: target logical unit number - * @m_page: L2P map information data for pre-request - * @len: length of host-side cached L2P map in m_page - * @lpn: start LPN of L2P map in m_page - */ -struct ufshpb_req { - struct request *req; - struct bio *bio; - struct ufshpb_lu *hpb; - struct list_head list_req; - union { - struct { - struct ufshpb_map_ctx *mctx; - unsigned int rgn_idx; - unsigned int srgn_idx; - unsigned int lun; - } rb; - struct { - struct page *m_page; - unsigned int len; - unsigned long lpn; - } wb; - }; -}; - -struct victim_select_info { - struct list_head lh_lru_rgn; /* LRU list of regions */ - int max_lru_active_cnt; /* supported hpb #region - pinned #region */ - atomic_t active_cnt; -}; - -/** - * ufshpb_params - ufs hpb parameters - * @requeue_timeout_ms - requeue threshold of wb command (0x2) - * @activation_thld - min reads [IOs] to activate/update a region - * @normalization_factor - shift right the region's reads - * @eviction_thld_enter - min reads [IOs] for the entering region in eviction - * @eviction_thld_exit - max reads [IOs] for the exiting region in eviction - * @read_timeout_ms - timeout [ms] from the last read IO to the region - * @read_timeout_expiries - amount of allowable timeout expireis - * @timeout_polling_interval_ms - frequency in which timeouts are checked - * @inflight_map_req - number of inflight map requests - */ -struct ufshpb_params { - unsigned int requeue_timeout_ms; - unsigned int activation_thld; - unsigned int normalization_factor; - unsigned int eviction_thld_enter; - unsigned int eviction_thld_exit; - unsigned int read_timeout_ms; - unsigned int read_timeout_expiries; - unsigned int timeout_polling_interval_ms; - unsigned int inflight_map_req; -}; - -struct ufshpb_stats { - u64 hit_cnt; - u64 miss_cnt; - u64 rcmd_noti_cnt; - u64 rcmd_active_cnt; - u64 rcmd_inactive_cnt; - u64 map_req_cnt; - u64 pre_req_cnt; - u64 umap_req_cnt; -}; - -struct ufshpb_lu { - int lun; - struct scsi_device *sdev_ufs_lu; - - spinlock_t rgn_state_lock; /* for protect rgn/srgn state */ - struct ufshpb_region *rgn_tbl; - - atomic_t hpb_state; - - spinlock_t rsp_list_lock; - struct list_head lh_act_srgn; /* hold rsp_list_lock */ - struct list_head lh_inact_rgn; /* hold rsp_list_lock */ - - /* pre request information */ - struct ufshpb_req *pre_req; - int num_inflight_pre_req; - int throttle_pre_req; - int num_inflight_map_req; /* hold param_lock */ - spinlock_t param_lock; - - struct list_head lh_pre_req_free; - int pre_req_max_tr_len; - - /* cached L2P map management worker */ - struct work_struct map_work; - - /* for selecting victim */ - struct victim_select_info lru_info; - struct work_struct ufshpb_normalization_work; - struct delayed_work ufshpb_read_to_work; - unsigned long work_data_bits; -#define TIMEOUT_WORK_RUNNING 0 - - /* pinned region information */ - u32 lu_pinned_start; - u32 lu_pinned_end; - - /* HPB related configuration */ - u32 rgns_per_lu; - u32 srgns_per_lu; - u32 last_srgn_entries; - int srgns_per_rgn; - u32 srgn_mem_size; - u32 entries_per_rgn_mask; - u32 entries_per_rgn_shift; - u32 entries_per_srgn; - u32 entries_per_srgn_mask; - u32 entries_per_srgn_shift; - u32 pages_per_srgn; - - bool is_hcm; - - struct ufshpb_stats stats; - struct ufshpb_params params; - - struct kmem_cache *map_req_cache; - struct kmem_cache *m_page_cache; - - struct list_head list_hpb_lu; -}; - -struct ufs_hba; -struct ufshcd_lrb; - -#ifndef CONFIG_SCSI_UFS_HPB -static int ufshpb_prep(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) { return 0; } -static void ufshpb_rsp_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) {} -static void ufshpb_resume(struct ufs_hba *hba) {} -static void ufshpb_suspend(struct ufs_hba *hba) {} -static void ufshpb_toggle_state(struct ufs_hba *hba, enum UFSHPB_STATE src, enum UFSHPB_STATE dest) {} -static void ufshpb_init(struct ufs_hba *hba) {} -static void ufshpb_init_hpb_lu(struct ufs_hba *hba, struct scsi_device *sdev) {} -static void ufshpb_destroy_lu(struct ufs_hba *hba, struct scsi_device *sdev) {} -static void ufshpb_remove(struct ufs_hba *hba) {} -static bool ufshpb_is_allowed(struct ufs_hba *hba) { return false; } -static void ufshpb_get_geo_info(struct ufs_hba *hba, u8 *geo_buf) {} -static void ufshpb_get_dev_info(struct ufs_hba *hba, u8 *desc_buf) {} -static bool ufshpb_is_legacy(struct ufs_hba *hba) { return false; } -#else -int ufshpb_prep(struct ufs_hba *hba, struct ufshcd_lrb *lrbp); -void ufshpb_rsp_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp); -void ufshpb_resume(struct ufs_hba *hba); -void ufshpb_suspend(struct ufs_hba *hba); -void ufshpb_toggle_state(struct ufs_hba *hba, enum UFSHPB_STATE src, enum UFSHPB_STATE dest); -void ufshpb_init(struct ufs_hba *hba); -void ufshpb_init_hpb_lu(struct ufs_hba *hba, struct scsi_device *sdev); -void ufshpb_destroy_lu(struct ufs_hba *hba, struct scsi_device *sdev); -void ufshpb_remove(struct ufs_hba *hba); -bool ufshpb_is_allowed(struct ufs_hba *hba); -void ufshpb_get_geo_info(struct ufs_hba *hba, u8 *geo_buf); -void ufshpb_get_dev_info(struct ufs_hba *hba, u8 *desc_buf); -bool ufshpb_is_legacy(struct ufs_hba *hba); -extern struct attribute_group ufs_sysfs_hpb_stat_group; -extern struct attribute_group ufs_sysfs_hpb_param_group; -#endif - -#endif /* End of Header */ diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h index a2bc025a748e9..0dd546a20503b 100644 --- a/include/ufs/ufs.h +++ b/include/ufs/ufs.h @@ -517,41 +517,6 @@ struct utp_cmd_rsp { u8 sense_data[UFS_SENSE_SIZE]; }; -struct ufshpb_active_field { - __be16 active_rgn; - __be16 active_srgn; -}; -#define HPB_ACT_FIELD_SIZE 4 - -/** - * struct utp_hpb_rsp - Response UPIU structure - * @residual_transfer_count: Residual transfer count DW-3 - * @reserved1: Reserved double words DW-4 to DW-7 - * @sense_data_len: Sense data length DW-8 U16 - * @desc_type: Descriptor type of sense data - * @additional_len: Additional length of sense data - * @hpb_op: HPB operation type - * @lun: LUN of response UPIU - * @active_rgn_cnt: Active region count - * @inactive_rgn_cnt: Inactive region count - * @hpb_active_field: Recommended to read HPB region and subregion - * @hpb_inactive_field: To be inactivated HPB region and subregion - */ -struct utp_hpb_rsp { - __be32 residual_transfer_count; - __be32 reserved1[4]; - __be16 sense_data_len; - u8 desc_type; - u8 additional_len; - u8 hpb_op; - u8 lun; - u8 active_rgn_cnt; - u8 inactive_rgn_cnt; - struct ufshpb_active_field hpb_active_field[2]; - __be16 hpb_inactive_field[2]; -}; -#define UTP_HPB_RSP_SIZE 40 - /** * struct utp_upiu_rsp - general upiu response structure * @header: UPIU header structure DW-0 to DW-2 @@ -562,7 +527,6 @@ struct utp_upiu_rsp { struct utp_upiu_header header; union { struct utp_cmd_rsp sr; - struct utp_hpb_rsp hr; struct utp_upiu_query qr; }; }; @@ -622,9 +586,6 @@ struct ufs_dev_info { /* Stores the depth of queue in UFS device */ u8 bqueuedepth; - /* UFS HPB related flag */ - bool hpb_enabled; - /* UFS WB related flags */ bool wb_enabled; bool wb_buf_flush_enabled; diff --git a/include/ufs/ufs_quirks.h b/include/ufs/ufs_quirks.h index bcb4f004bed57..41ff44dfa1db3 100644 --- a/include/ufs/ufs_quirks.h +++ b/include/ufs/ufs_quirks.h @@ -107,10 +107,4 @@ struct ufs_dev_quirk { */ #define UFS_DEVICE_QUIRK_DELAY_AFTER_LPM (1 << 11) -/* - * Some UFS devices require L2P entry should be swapped before being sent to the - * UFS device for HPB READ command. - */ -#define UFS_DEVICE_QUIRK_SWAP_L2P_ENTRY_FOR_HPB_READ (1 << 12) - #endif /* UFS_QUIRKS_H_ */ diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 9f579640b9094..fc80de57a4c64 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -709,31 +709,6 @@ struct ufs_hba_variant_params { u32 wb_flush_threshold; }; -#ifdef CONFIG_SCSI_UFS_HPB -/** - * struct ufshpb_dev_info - UFSHPB device related info - * @num_lu: the number of user logical unit to check whether all lu finished - * initialization - * @rgn_size: device reported HPB region size - * @srgn_size: device reported HPB sub-region size - * @slave_conf_cnt: counter to check all lu finished initialization - * @hpb_disabled: flag to check if HPB is disabled - * @max_hpb_single_cmd: device reported bMAX_DATA_SIZE_FOR_SINGLE_CMD value - * @is_legacy: flag to check HPB 1.0 - * @control_mode: either host or device - */ -struct ufshpb_dev_info { - int num_lu; - int rgn_size; - int srgn_size; - atomic_t slave_conf_cnt; - bool hpb_disabled; - u8 max_hpb_single_cmd; - bool is_legacy; - u8 control_mode; -}; -#endif - struct ufs_hba_monitor { unsigned long chunk_size; @@ -894,7 +869,6 @@ enum ufshcd_mcq_opr { * @rpm_dev_flush_recheck_work: used to suspend from RPM (runtime power * management) after the UFS device has finished a WriteBooster buffer * flush or auto BKOP. - * @ufshpb_dev: information related to HPB (Host Performance Booster). * @monitor: statistics about UFS commands * @crypto_capabilities: Content of crypto capabilities register (0x100) * @crypto_cap_array: Array of crypto capabilities @@ -1050,10 +1024,6 @@ struct ufs_hba { struct request_queue *bsg_queue; struct delayed_work rpm_dev_flush_recheck_work; -#ifdef CONFIG_SCSI_UFS_HPB - struct ufshpb_dev_info ufshpb_dev; -#endif - struct ufs_hba_monitor monitor; #ifdef CONFIG_SCSI_UFS_CRYPTO -- GitLab From 86fe3e9f4c635cf740b31161ee35aed4a78e03f9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 18 Jul 2023 10:02:49 +0300 Subject: [PATCH 0356/3445] phy: starfive: fix error code in probe This is using the wrong pointer, "phy->regs" vs "phy->phy". Fixes: fd097f48eea9 ("phy: starfive: Add JH7110 PCIE 2.0 PHY driver") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/3cc81f2a-efd7-4ef7-ae6b-e38c91efe153@moroto.mountain Signed-off-by: Vinod Koul --- drivers/phy/starfive/phy-jh7110-pcie.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/starfive/phy-jh7110-pcie.c b/drivers/phy/starfive/phy-jh7110-pcie.c index cbe79c1f59d33..734c8e0077277 100644 --- a/drivers/phy/starfive/phy-jh7110-pcie.c +++ b/drivers/phy/starfive/phy-jh7110-pcie.c @@ -151,7 +151,7 @@ static int jh7110_pcie_phy_probe(struct platform_device *pdev) phy->phy = devm_phy_create(dev, NULL, &jh7110_pcie_phy_ops); if (IS_ERR(phy->phy)) - return dev_err_probe(dev, PTR_ERR(phy->regs), + return dev_err_probe(dev, PTR_ERR(phy->phy), "Failed to map phy base\n"); phy->sys_syscon = -- GitLab From ae07a9a865a4eb30223c21eae70ddb189da6ee9a Mon Sep 17 00:00:00 2001 From: Changhuang Liang Date: Tue, 18 Jul 2023 00:08:02 -0700 Subject: [PATCH 0357/3445] dt-bindings: phy: Add starfive,jh7110-dphy-rx StarFive SoCs like the jh7110 use a MIPI D-PHY RX controller based on a M31 IP. Add a binding for it. Signed-off-by: Changhuang Liang Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230718070803.16660-2-changhuang.liang@starfivetech.com Signed-off-by: Vinod Koul --- .../bindings/phy/starfive,jh7110-dphy-rx.yaml | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/starfive,jh7110-dphy-rx.yaml diff --git a/Documentation/devicetree/bindings/phy/starfive,jh7110-dphy-rx.yaml b/Documentation/devicetree/bindings/phy/starfive,jh7110-dphy-rx.yaml new file mode 100644 index 0000000000000..7224cde6fce01 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/starfive,jh7110-dphy-rx.yaml @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/starfive,jh7110-dphy-rx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive SoC JH7110 MIPI D-PHY Rx Controller + +maintainers: + - Jack Zhu + - Changhuang Liang + +description: + StarFive SoCs contain a MIPI CSI D-PHY based on M31 IP, used to + transfer CSI camera data. + +properties: + compatible: + const: starfive,jh7110-dphy-rx + + reg: + maxItems: 1 + + clocks: + items: + - description: config clock + - description: reference clock + - description: escape mode transmit clock + + clock-names: + items: + - const: cfg + - const: ref + - const: tx + + resets: + items: + - description: DPHY_HW reset + - description: DPHY_B09_ALWAYS_ON reset + + power-domains: + maxItems: 1 + + "#phy-cells": + const: 0 + +required: + - compatible + - reg + - clocks + - clock-names + - resets + - power-domains + - "#phy-cells" + +additionalProperties: false + +examples: + - | + phy@19820000 { + compatible = "starfive,jh7110-dphy-rx"; + reg = <0x19820000 0x10000>; + clocks = <&ispcrg 3>, + <&ispcrg 4>, + <&ispcrg 5>; + clock-names = "cfg", "ref", "tx"; + resets = <&ispcrg 2>, + <&ispcrg 3>; + power-domains = <&aon_syscon 1>; + #phy-cells = <0>; + }; -- GitLab From f8aa660841bca12aed51c967ed9bdaf1d97996ed Mon Sep 17 00:00:00 2001 From: Changhuang Liang Date: Tue, 18 Jul 2023 00:08:03 -0700 Subject: [PATCH 0358/3445] phy: starfive: Add mipi dphy rx support Add mipi dphy rx support for the StarFive JH7110 SoC. It is used to transfer CSI camera data. Signed-off-by: Changhuang Liang Reviewed-by: Minda Chen Link: https://lore.kernel.org/r/20230718070803.16660-3-changhuang.liang@starfivetech.com Signed-off-by: Vinod Koul --- MAINTAINERS | 7 + drivers/phy/starfive/Kconfig | 9 + drivers/phy/starfive/Makefile | 5 +- drivers/phy/starfive/phy-jh7110-dphy-rx.c | 232 ++++++++++++++++++++++ 4 files changed, 251 insertions(+), 2 deletions(-) create mode 100644 drivers/phy/starfive/phy-jh7110-dphy-rx.c diff --git a/MAINTAINERS b/MAINTAINERS index 621b4147d4702..0f28f3f8f7008 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20265,6 +20265,13 @@ S: Maintained F: Documentation/devicetree/bindings/net/starfive,jh7110-dwmac.yaml F: drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c +STARFIVE JH7110 DPHY RX DRIVER +M: Jack Zhu +M: Changhuang Liang +S: Supported +F: Documentation/devicetree/bindings/phy/starfive,jh7110-dphy-rx.yaml +F: drivers/phy/starfive/phy-starfive-dphy-rx.c + STARFIVE JH7110 MMC/SD/SDIO DRIVER M: William Qiu S: Supported diff --git a/drivers/phy/starfive/Kconfig b/drivers/phy/starfive/Kconfig index da9a98cdf7e39..a560533a674ee 100644 --- a/drivers/phy/starfive/Kconfig +++ b/drivers/phy/starfive/Kconfig @@ -3,6 +3,15 @@ # Phy drivers for StarFive platforms # +config PHY_STARFIVE_JH7110_DPHY_RX + tristate "StarFive JH7110 D-PHY RX support" + select GENERIC_PHY + select GENERIC_PHY_MIPI_DPHY + help + Choose this option if you have a StarFive D-PHY in your + system. If M is selected, the module will be called + phy-jh7110-dphy-rx.ko. + config PHY_STARFIVE_JH7110_PCIE tristate "Starfive JH7110 PCIE 2.0/USB 3.0 PHY support" depends on HAS_IOMEM diff --git a/drivers/phy/starfive/Makefile b/drivers/phy/starfive/Makefile index 1c62d93e32805..b391018b7c471 100644 --- a/drivers/phy/starfive/Makefile +++ b/drivers/phy/starfive/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_PHY_STARFIVE_JH7110_PCIE) += phy-jh7110-pcie.o -obj-$(CONFIG_PHY_STARFIVE_JH7110_USB) += phy-jh7110-usb.o +obj-$(CONFIG_PHY_STARFIVE_JH7110_DPHY_RX) += phy-jh7110-dphy-rx.o +obj-$(CONFIG_PHY_STARFIVE_JH7110_PCIE) += phy-jh7110-pcie.o +obj-$(CONFIG_PHY_STARFIVE_JH7110_USB) += phy-jh7110-usb.o diff --git a/drivers/phy/starfive/phy-jh7110-dphy-rx.c b/drivers/phy/starfive/phy-jh7110-dphy-rx.c new file mode 100644 index 0000000000000..037a9e0263cda --- /dev/null +++ b/drivers/phy/starfive/phy-jh7110-dphy-rx.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * StarFive JH7110 DPHY RX driver + * + * Copyright (C) 2023 StarFive Technology Co., Ltd. + * Author: Jack Zhu + * Author: Changhuang Liang + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STF_DPHY_APBCFGSAIF_SYSCFG(x) (x) + +#define STF_DPHY_ENABLE_CLK BIT(6) +#define STF_DPHY_ENABLE_CLK1 BIT(7) +#define STF_DPHY_ENABLE_LAN0 BIT(8) +#define STF_DPHY_ENABLE_LAN1 BIT(9) +#define STF_DPHY_ENABLE_LAN2 BIT(10) +#define STF_DPHY_ENABLE_LAN3 BIT(11) +#define STF_DPHY_LANE_SWAP_CLK GENMASK(22, 20) +#define STF_DPHY_LANE_SWAP_CLK1 GENMASK(25, 23) +#define STF_DPHY_LANE_SWAP_LAN0 GENMASK(28, 26) +#define STF_DPHY_LANE_SWAP_LAN1 GENMASK(31, 29) + +#define STF_DPHY_LANE_SWAP_LAN2 GENMASK(2, 0) +#define STF_DPHY_LANE_SWAP_LAN3 GENMASK(5, 3) +#define STF_DPHY_PLL_CLK_SEL GENMASK(21, 12) +#define STF_DPHY_PRECOUNTER_IN_CLK GENMASK(29, 22) + +#define STF_DPHY_PRECOUNTER_IN_CLK1 GENMASK(7, 0) +#define STF_DPHY_PRECOUNTER_IN_LAN0 GENMASK(15, 8) +#define STF_DPHY_PRECOUNTER_IN_LAN1 GENMASK(23, 16) +#define STF_DPHY_PRECOUNTER_IN_LAN2 GENMASK(31, 24) + +#define STF_DPHY_PRECOUNTER_IN_LAN3 GENMASK(7, 0) +#define STF_DPHY_RX_1C2C_SEL BIT(8) + +#define STF_MAP_LANES_NUM 6 + +struct regval { + u32 addr; + u32 val; +}; + +struct stf_dphy_info { + /** + * @maps: + * + * Physical lanes and logic lanes mapping table. + * + * The default order is: + * [clk lane0, data lane 0, data lane 1, data lane 2, date lane 3, clk lane 1] + */ + u8 maps[STF_MAP_LANES_NUM]; +}; + +struct stf_dphy { + struct device *dev; + void __iomem *regs; + struct clk *cfg_clk; + struct clk *ref_clk; + struct clk *tx_clk; + struct reset_control *rstc; + struct regulator *mipi_0p9; + struct phy *phy; + const struct stf_dphy_info *info; +}; + +static int stf_dphy_configure(struct phy *phy, union phy_configure_opts *opts) +{ + struct stf_dphy *dphy = phy_get_drvdata(phy); + const struct stf_dphy_info *info = dphy->info; + + writel(FIELD_PREP(STF_DPHY_ENABLE_CLK, 1) | + FIELD_PREP(STF_DPHY_ENABLE_CLK1, 1) | + FIELD_PREP(STF_DPHY_ENABLE_LAN0, 1) | + FIELD_PREP(STF_DPHY_ENABLE_LAN1, 1) | + FIELD_PREP(STF_DPHY_ENABLE_LAN2, 1) | + FIELD_PREP(STF_DPHY_ENABLE_LAN3, 1) | + FIELD_PREP(STF_DPHY_LANE_SWAP_CLK, info->maps[0]) | + FIELD_PREP(STF_DPHY_LANE_SWAP_CLK1, info->maps[5]) | + FIELD_PREP(STF_DPHY_LANE_SWAP_LAN0, info->maps[1]) | + FIELD_PREP(STF_DPHY_LANE_SWAP_LAN1, info->maps[2]), + dphy->regs + STF_DPHY_APBCFGSAIF_SYSCFG(188)); + + writel(FIELD_PREP(STF_DPHY_LANE_SWAP_LAN2, info->maps[3]) | + FIELD_PREP(STF_DPHY_LANE_SWAP_LAN3, info->maps[4]) | + FIELD_PREP(STF_DPHY_PRECOUNTER_IN_CLK, 8), + dphy->regs + STF_DPHY_APBCFGSAIF_SYSCFG(192)); + + writel(FIELD_PREP(STF_DPHY_PRECOUNTER_IN_CLK1, 8) | + FIELD_PREP(STF_DPHY_PRECOUNTER_IN_LAN0, 7) | + FIELD_PREP(STF_DPHY_PRECOUNTER_IN_LAN1, 7) | + FIELD_PREP(STF_DPHY_PRECOUNTER_IN_LAN2, 7), + dphy->regs + STF_DPHY_APBCFGSAIF_SYSCFG(196)); + + writel(FIELD_PREP(STF_DPHY_PRECOUNTER_IN_LAN3, 7), + dphy->regs + STF_DPHY_APBCFGSAIF_SYSCFG(200)); + + return 0; +} + +static int stf_dphy_power_on(struct phy *phy) +{ + struct stf_dphy *dphy = phy_get_drvdata(phy); + int ret; + + ret = pm_runtime_resume_and_get(dphy->dev); + if (ret < 0) + return ret; + + ret = regulator_enable(dphy->mipi_0p9); + if (ret) { + pm_runtime_put(dphy->dev); + return ret; + } + + clk_set_rate(dphy->cfg_clk, 99000000); + clk_set_rate(dphy->ref_clk, 49500000); + clk_set_rate(dphy->tx_clk, 19800000); + reset_control_deassert(dphy->rstc); + + return 0; +} + +static int stf_dphy_power_off(struct phy *phy) +{ + struct stf_dphy *dphy = phy_get_drvdata(phy); + + reset_control_assert(dphy->rstc); + + regulator_disable(dphy->mipi_0p9); + + pm_runtime_put_sync(dphy->dev); + + return 0; +} + +static const struct phy_ops stf_dphy_ops = { + .configure = stf_dphy_configure, + .power_on = stf_dphy_power_on, + .power_off = stf_dphy_power_off, +}; + +static int stf_dphy_probe(struct platform_device *pdev) +{ + struct phy_provider *phy_provider; + struct stf_dphy *dphy; + + dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL); + if (!dphy) + return -ENOMEM; + + dphy->info = of_device_get_match_data(&pdev->dev); + + dev_set_drvdata(&pdev->dev, dphy); + dphy->dev = &pdev->dev; + + dphy->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(dphy->regs)) + return PTR_ERR(dphy->regs); + + dphy->cfg_clk = devm_clk_get(&pdev->dev, "cfg"); + if (IS_ERR(dphy->cfg_clk)) + return PTR_ERR(dphy->cfg_clk); + + dphy->ref_clk = devm_clk_get(&pdev->dev, "ref"); + if (IS_ERR(dphy->ref_clk)) + return PTR_ERR(dphy->ref_clk); + + dphy->tx_clk = devm_clk_get(&pdev->dev, "tx"); + if (IS_ERR(dphy->tx_clk)) + return PTR_ERR(dphy->tx_clk); + + dphy->rstc = devm_reset_control_array_get_exclusive(&pdev->dev); + if (IS_ERR(dphy->rstc)) + return PTR_ERR(dphy->rstc); + + dphy->mipi_0p9 = devm_regulator_get(&pdev->dev, "mipi_0p9"); + if (IS_ERR(dphy->mipi_0p9)) + return PTR_ERR(dphy->mipi_0p9); + + dphy->phy = devm_phy_create(&pdev->dev, NULL, &stf_dphy_ops); + if (IS_ERR(dphy->phy)) { + dev_err(&pdev->dev, "Failed to create PHY\n"); + return PTR_ERR(dphy->phy); + } + + pm_runtime_enable(&pdev->dev); + + phy_set_drvdata(dphy->phy, dphy); + phy_provider = devm_of_phy_provider_register(&pdev->dev, + of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct stf_dphy_info starfive_dphy_info = { + .maps = {4, 0, 1, 2, 3, 5}, +}; + +static const struct of_device_id stf_dphy_dt_ids[] = { + { + .compatible = "starfive,jh7110-dphy-rx", + .data = &starfive_dphy_info, + }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, stf_dphy_dt_ids); + +static struct platform_driver stf_dphy_driver = { + .probe = stf_dphy_probe, + .driver = { + .name = "starfive-dphy-rx", + .of_match_table = stf_dphy_dt_ids, + }, +}; +module_platform_driver(stf_dphy_driver); + +MODULE_AUTHOR("Jack Zhu "); +MODULE_AUTHOR("Changhuang Liang "); +MODULE_DESCRIPTION("StarFive JH7110 DPHY RX driver"); +MODULE_LICENSE("GPL"); -- GitLab From f5a8ecef3c6b840673d08342045c3014d674555f Mon Sep 17 00:00:00 2001 From: Yang Li Date: Wed, 19 Jul 2023 08:36:14 +0800 Subject: [PATCH 0359/3445] phy: Remove duplicated include in xusb.c ./drivers/phy/tegra/xusb.c: linux/platform_device.h is included more than once. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=5930 Signed-off-by: Yang Li Acked-by: Thierry Reding Link: https://lore.kernel.org/r/20230719003614.5506-1-yang.lee@linux.alibaba.com Signed-off-by: Vinod Koul --- drivers/phy/tegra/xusb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c index ed30866e7647d..142ebe0247cc0 100644 --- a/drivers/phy/tegra/xusb.c +++ b/drivers/phy/tegra/xusb.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include -- GitLab From 57a79ce964d76757c2fd21e097bcd9eb44884def Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 11 Jul 2023 15:09:07 +0300 Subject: [PATCH 0360/3445] dt-bindings: phy: migrate combo QMP PHY bindings to qcom,sc8280xp-qmp-usb43dp-phy.yaml Migrate legacy bindings (described in qcom,sc7180-qmp-usb3-dp-phy.yaml) to qcom,sc8280xp-qmp-usb43dp-phy.yaml. This removes a need to declare the child PHY node or split resource regions. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230711120916.4165894-2-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- .../phy/qcom,sc7180-qmp-usb3-dp-phy.yaml | 284 ------------------ .../phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml | 46 ++- 2 files changed, 44 insertions(+), 286 deletions(-) delete mode 100644 Documentation/devicetree/bindings/phy/qcom,sc7180-qmp-usb3-dp-phy.yaml diff --git a/Documentation/devicetree/bindings/phy/qcom,sc7180-qmp-usb3-dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc7180-qmp-usb3-dp-phy.yaml deleted file mode 100644 index 3c97289383917..0000000000000 --- a/Documentation/devicetree/bindings/phy/qcom,sc7180-qmp-usb3-dp-phy.yaml +++ /dev/null @@ -1,284 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) - -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/phy/qcom,sc7180-qmp-usb3-dp-phy.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Qualcomm QMP USB3 DP PHY controller (SC7180) - -description: - The QMP PHY controller supports physical layer functionality for a number of - controllers on Qualcomm chipsets, such as, PCIe, UFS and USB. - - Note that these bindings are for SoCs up to SC8180X. For newer SoCs, see - qcom,sc8280xp-qmp-usb43dp-phy.yaml. - -maintainers: - - Wesley Cheng - -properties: - compatible: - oneOf: - - enum: - - qcom,sc7180-qmp-usb3-dp-phy - - qcom,sc8180x-qmp-usb3-dp-phy - - qcom,sdm845-qmp-usb3-dp-phy - - qcom,sm8150-qmp-usb3-dp-phy - - qcom,sm8250-qmp-usb3-dp-phy - - items: - - enum: - - qcom,sc7280-qmp-usb3-dp-phy - - const: qcom,sm8250-qmp-usb3-dp-phy - - reg: - items: - - description: Address and length of PHY's USB serdes block. - - description: Address and length of the DP_COM control block. - - description: Address and length of PHY's DP serdes block. - - reg-names: - items: - - const: usb - - const: dp_com - - const: dp - - "#address-cells": - enum: [ 1, 2 ] - - "#size-cells": - enum: [ 1, 2 ] - - ranges: true - - clocks: - minItems: 3 - maxItems: 4 - - clock-names: - minItems: 3 - maxItems: 4 - - power-domains: - maxItems: 1 - - orientation-switch: - description: Flag the port as possible handler of orientation switching - type: boolean - - resets: - items: - - description: reset of phy block. - - description: phy common block reset. - - reset-names: - items: - - const: phy - - const: common - - vdda-phy-supply: - description: - Phandle to a regulator supply to PHY core block. - - vdda-pll-supply: - description: - Phandle to 1.8V regulator supply to PHY refclk pll block. - - vddp-ref-clk-supply: - description: - Phandle to a regulator supply to any specific refclk pll block. - -# Required nodes: -patternProperties: - "^usb3-phy@[0-9a-f]+$": - type: object - additionalProperties: false - description: - The USB3 PHY. - - properties: - reg: - items: - - description: Address and length of TX. - - description: Address and length of RX. - - description: Address and length of PCS. - - description: Address and length of TX2. - - description: Address and length of RX2. - - description: Address and length of pcs_misc. - - clocks: - items: - - description: pipe clock - - clock-names: - deprecated: true - items: - - const: pipe0 - - clock-output-names: - items: - - const: usb3_phy_pipe_clk_src - - '#clock-cells': - const: 0 - - '#phy-cells': - const: 0 - - required: - - reg - - clocks - - '#clock-cells' - - '#phy-cells' - - "^dp-phy@[0-9a-f]+$": - type: object - additionalProperties: false - description: - The DP PHY. - - properties: - reg: - items: - - description: Address and length of TX. - - description: Address and length of RX. - - description: Address and length of PCS. - - description: Address and length of TX2. - - description: Address and length of RX2. - - '#clock-cells': - const: 1 - - '#phy-cells': - const: 0 - - required: - - reg - - '#clock-cells' - - '#phy-cells' - -required: - - compatible - - reg - - "#address-cells" - - "#size-cells" - - ranges - - clocks - - clock-names - - resets - - reset-names - - vdda-phy-supply - - vdda-pll-supply - -allOf: - - if: - properties: - compatible: - enum: - - qcom,sc7180-qmp-usb3-dp-phy - - qcom,sdm845-qmp-usb3-dp-phy - then: - properties: - clocks: - items: - - description: Phy aux clock - - description: Phy config clock - - description: 19.2 MHz ref clk - - description: Phy common block aux clock - clock-names: - items: - - const: aux - - const: cfg_ahb - - const: ref - - const: com_aux - - - if: - properties: - compatible: - enum: - - qcom,sc8180x-qmp-usb3-dp-phy - - qcom,sm8150-qmp-usb3-dp-phy - then: - properties: - clocks: - items: - - description: Phy aux clock - - description: 19.2 MHz ref clk - - description: Phy common block aux clock - clock-names: - items: - - const: aux - - const: ref - - const: com_aux - - - if: - properties: - compatible: - enum: - - qcom,sm8250-qmp-usb3-dp-phy - then: - properties: - clocks: - items: - - description: Phy aux clock - - description: Board XO source - - description: Phy common block aux clock - clock-names: - items: - - const: aux - - const: ref_clk_src - - const: com_aux - -additionalProperties: false - -examples: - - | - #include - usb_1_qmpphy: phy-wrapper@88e9000 { - compatible = "qcom,sdm845-qmp-usb3-dp-phy"; - reg = <0x088e9000 0x18c>, - <0x088e8000 0x10>, - <0x088ea000 0x40>; - reg-names = "usb", "dp_com", "dp"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0x088e9000 0x2000>; - - clocks = <&gcc GCC_USB3_PRIM_PHY_AUX_CLK>, - <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, - <&gcc GCC_USB3_PRIM_CLKREF_CLK>, - <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>; - clock-names = "aux", "cfg_ahb", "ref", "com_aux"; - - resets = <&gcc GCC_USB3_PHY_PRIM_BCR>, - <&gcc GCC_USB3_DP_PHY_PRIM_BCR>; - reset-names = "phy", "common"; - - vdda-phy-supply = <&vdda_usb2_ss_1p2>; - vdda-pll-supply = <&vdda_usb2_ss_core>; - - orientation-switch; - - usb3-phy@200 { - reg = <0x200 0x128>, - <0x400 0x200>, - <0xc00 0x218>, - <0x600 0x128>, - <0x800 0x200>, - <0xa00 0x100>; - #clock-cells = <0>; - #phy-cells = <0>; - clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; - clock-output-names = "usb3_phy_pipe_clk_src"; - }; - - dp-phy@88ea200 { - reg = <0xa200 0x200>, - <0xa400 0x200>, - <0xaa00 0x200>, - <0xa600 0x200>, - <0xa800 0x200>; - #clock-cells = <1>; - #phy-cells = <0>; - }; - }; diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml index ef1c02d8ac88e..9af203dc8793f 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml @@ -16,8 +16,14 @@ description: properties: compatible: enum: + - qcom,sc7180-qmp-usb3-dp-phy + - qcom,sc7280-qmp-usb3-dp-phy + - qcom,sc8180x-qmp-usb3-dp-phy - qcom,sc8280xp-qmp-usb43dp-phy + - qcom,sdm845-qmp-usb3-dp-phy - qcom,sm6350-qmp-usb3-dp-phy + - qcom,sm8150-qmp-usb3-dp-phy + - qcom,sm8250-qmp-usb3-dp-phy - qcom,sm8350-qmp-usb3-dp-phy - qcom,sm8450-qmp-usb3-dp-phy - qcom,sm8550-qmp-usb3-dp-phy @@ -26,14 +32,17 @@ properties: maxItems: 1 clocks: - maxItems: 4 + minItems: 4 + maxItems: 5 clock-names: + minItems: 4 items: - const: aux - const: ref - const: com_aux - const: usb3_pipe + - const: cfg_ahb power-domains: maxItems: 1 @@ -85,7 +94,6 @@ required: - reg - clocks - clock-names - - power-domains - resets - reset-names - vdda-phy-supply @@ -93,6 +101,40 @@ required: - "#clock-cells" - "#phy-cells" +allOf: + - if: + properties: + compatible: + enum: + - qcom,sc7180-qmp-usb3-dp-phy + - qcom,sdm845-qmp-usb3-dp-phy + then: + properties: + clocks: + maxItems: 5 + clock-names: + maxItems: 5 + else: + properties: + clocks: + maxItems: 4 + clock-names: + maxItems: 4 + + - if: + properties: + compatible: + enum: + - qcom,sc8280xp-qmp-usb43dp-phy + - qcom,sm6350-qmp-usb3-dp-phy + - qcom,sm8550-qmp-usb3-dp-phy + then: + required: + - power-domains + else: + properties: + power-domains: false + additionalProperties: false examples: -- GitLab From 28e265bf84a8f885b3156f24dc246bf1d7bb40a5 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 11 Jul 2023 15:09:08 +0300 Subject: [PATCH 0361/3445] phy: qcom-qmp-combo: simplify clock handling For the existing PHYs for new binding we are going to drop ref_clk_src clock and always use ref clock. Rather than introducing additional code to handle legacy vs current bindings (and clock names), use devm_clk_bulk_get_optional() when new bindings are used and devm_clk_bulk_get_all() when legacy bindings are in place. Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230711120916.4165894-3-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 67 ++++++++--------------- 1 file changed, 23 insertions(+), 44 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index e373b6b1ee996..0220924a5114b 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -1358,9 +1358,6 @@ struct qmp_phy_cfg { int (*calibrate_dp_phy)(struct qmp_combo *qmp); void (*dp_aux_init)(struct qmp_combo *qmp); - /* clock ids to be requested */ - const char * const *clk_list; - int num_clks; /* resets to be requested */ const char * const *reset_list; int num_resets; @@ -1402,6 +1399,7 @@ struct qmp_combo { struct clk *pipe_clk; struct clk_bulk_data *clks; + int num_clks; struct reset_control_bulk_data *resets; struct regulator_bulk_data *vregs; @@ -1462,19 +1460,10 @@ static inline void qphy_clrbits(void __iomem *base, u32 offset, u32 val) } /* list of clocks required by phy */ -static const char * const qmp_v3_phy_clk_l[] = { +static const char * const qmp_combo_phy_clk_l[] = { "aux", "cfg_ahb", "ref", "com_aux", }; -static const char * const qmp_v4_phy_clk_l[] = { - "aux", "ref", "com_aux", -}; - -/* the primary usb3 phy on sm8250 doesn't have a ref clock */ -static const char * const qmp_v4_sm8250_usbphy_clk_l[] = { - "aux", "ref_clk_src", "com_aux" -}; - /* list of resets */ static const char * const msm8996_usb3phy_reset_l[] = { "phy", "common", @@ -1548,8 +1537,6 @@ static const struct qmp_phy_cfg sc7180_usb3dpphy_cfg = { .configure_dp_phy = qmp_v3_configure_dp_phy, .calibrate_dp_phy = qmp_v3_calibrate_dp_phy, - .clk_list = qmp_v3_phy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l), .reset_list = sc7180_usb3phy_reset_l, .num_resets = ARRAY_SIZE(sc7180_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, @@ -1593,8 +1580,6 @@ static const struct qmp_phy_cfg sdm845_usb3dpphy_cfg = { .configure_dp_phy = qmp_v3_configure_dp_phy, .calibrate_dp_phy = qmp_v3_calibrate_dp_phy, - .clk_list = qmp_v3_phy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l), .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, @@ -1640,8 +1625,6 @@ static const struct qmp_phy_cfg sc8180x_usb3dpphy_cfg = { .configure_dp_phy = qmp_v4_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, - .clk_list = qmp_v4_phy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l), .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, @@ -1688,8 +1671,6 @@ static const struct qmp_phy_cfg sc8280xp_usb43dpphy_cfg = { .configure_dp_phy = qmp_v4_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, - .clk_list = qmp_v4_phy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l), .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, @@ -1733,8 +1714,6 @@ static const struct qmp_phy_cfg sm6350_usb3dpphy_cfg = { .configure_dp_phy = qmp_v3_configure_dp_phy, .calibrate_dp_phy = qmp_v3_calibrate_dp_phy, - .clk_list = qmp_v4_phy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l), .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, @@ -1778,8 +1757,6 @@ static const struct qmp_phy_cfg sm8250_usb3dpphy_cfg = { .configure_dp_phy = qmp_v4_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, - .clk_list = qmp_v4_sm8250_usbphy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v4_sm8250_usbphy_clk_l), .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, @@ -1828,8 +1805,6 @@ static const struct qmp_phy_cfg sm8350_usb3dpphy_cfg = { .configure_dp_phy = qmp_v4_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, - .clk_list = qmp_v4_phy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l), .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, @@ -1878,8 +1853,6 @@ static const struct qmp_phy_cfg sm8550_usb3dpphy_cfg = { .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, .regs = qmp_v6_usb3phy_regs_layout, - .clk_list = qmp_v4_phy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l), .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, @@ -2432,7 +2405,7 @@ static int qmp_combo_com_init(struct qmp_combo *qmp, bool force) goto err_disable_regulators; } - ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks); + ret = clk_bulk_prepare_enable(qmp->num_clks, qmp->clks); if (ret) goto err_assert_reset; @@ -2482,7 +2455,7 @@ static int qmp_combo_com_exit(struct qmp_combo *qmp, bool force) reset_control_bulk_assert(cfg->num_resets, qmp->resets); - clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks); + clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); regulator_bulk_disable(cfg->num_vregs, qmp->vregs); @@ -2761,7 +2734,6 @@ static void qmp_combo_disable_autonomous_mode(struct qmp_combo *qmp) static int __maybe_unused qmp_combo_runtime_suspend(struct device *dev) { struct qmp_combo *qmp = dev_get_drvdata(dev); - const struct qmp_phy_cfg *cfg = qmp->cfg; dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode); @@ -2773,7 +2745,7 @@ static int __maybe_unused qmp_combo_runtime_suspend(struct device *dev) qmp_combo_enable_autonomous_mode(qmp); clk_disable_unprepare(qmp->pipe_clk); - clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks); + clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); return 0; } @@ -2781,7 +2753,6 @@ static int __maybe_unused qmp_combo_runtime_suspend(struct device *dev) static int __maybe_unused qmp_combo_runtime_resume(struct device *dev) { struct qmp_combo *qmp = dev_get_drvdata(dev); - const struct qmp_phy_cfg *cfg = qmp->cfg; int ret = 0; dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode); @@ -2791,14 +2762,14 @@ static int __maybe_unused qmp_combo_runtime_resume(struct device *dev) return 0; } - ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks); + ret = clk_bulk_prepare_enable(qmp->num_clks, qmp->clks); if (ret) return ret; ret = clk_prepare_enable(qmp->pipe_clk); if (ret) { dev_err(dev, "pipe_clk enable failed, err=%d\n", ret); - clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks); + clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); return ret; } @@ -2869,9 +2840,8 @@ static int qmp_combo_reset_init(struct qmp_combo *qmp) static int qmp_combo_clk_init(struct qmp_combo *qmp) { - const struct qmp_phy_cfg *cfg = qmp->cfg; struct device *dev = qmp->dev; - int num = cfg->num_clks; + int num = ARRAY_SIZE(qmp_combo_phy_clk_l); int i; qmp->clks = devm_kcalloc(dev, num, sizeof(*qmp->clks), GFP_KERNEL); @@ -2879,9 +2849,11 @@ static int qmp_combo_clk_init(struct qmp_combo *qmp) return -ENOMEM; for (i = 0; i < num; i++) - qmp->clks[i].id = cfg->clk_list[i]; + qmp->clks[i].id = qmp_combo_phy_clk_l[i]; - return devm_clk_bulk_get(dev, num, qmp->clks); + qmp->num_clks = num; + + return devm_clk_bulk_get_optional(dev, num, qmp->clks); } static void phy_clk_release_provider(void *res) @@ -3087,6 +3059,12 @@ static int phy_dp_clks_register(struct qmp_combo *qmp, struct device_node *np) if (ret) return ret; + ret = devm_clk_bulk_get_all(qmp->dev, &qmp->clks); + if (ret < 0) + return ret; + + qmp->num_clks = ret; + return 0; } @@ -3356,6 +3334,7 @@ static int qmp_combo_parse_dt(struct qmp_combo *qmp) const struct qmp_combo_offsets *offs = cfg->offsets; struct device *dev = qmp->dev; void __iomem *base; + int ret; if (!offs) return -EINVAL; @@ -3385,6 +3364,10 @@ static int qmp_combo_parse_dt(struct qmp_combo *qmp) } qmp->dp_dp_phy = base + offs->dp_dp_phy; + ret = qmp_combo_clk_init(qmp); + if (ret) + return ret; + qmp->pipe_clk = devm_clk_get(dev, "usb3_pipe"); if (IS_ERR(qmp->pipe_clk)) { return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk), @@ -3433,10 +3416,6 @@ static int qmp_combo_probe(struct platform_device *pdev) mutex_init(&qmp->phy_mutex); - ret = qmp_combo_clk_init(qmp); - if (ret) - return ret; - ret = qmp_combo_reset_init(qmp); if (ret) return ret; -- GitLab From a542ae82dfdd1e84f84593161ffc586e72cc992d Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 11 Jul 2023 15:09:09 +0300 Subject: [PATCH 0362/3445] phy: qcom-qmp-combo: populate offsets for all combo PHYs In order to support newer style bindings for combo PHYs, populate offsets for all Combo QMP PHY configurations. Reviewed-by: Neil Armstrong Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230711120916.4165894-4-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index 0220924a5114b..f7b7201d6d9f0 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -1504,6 +1504,8 @@ static const struct qmp_combo_offsets qmp_combo_offsets_v5 = { }; static const struct qmp_phy_cfg sc7180_usb3dpphy_cfg = { + .offsets = &qmp_combo_offsets_v3, + .serdes_tbl = qmp_v3_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl), .tx_tbl = qmp_v3_usb3_tx_tbl, @@ -1547,6 +1549,8 @@ static const struct qmp_phy_cfg sc7180_usb3dpphy_cfg = { }; static const struct qmp_phy_cfg sdm845_usb3dpphy_cfg = { + .offsets = &qmp_combo_offsets_v3, + .serdes_tbl = qmp_v3_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl), .tx_tbl = qmp_v3_usb3_tx_tbl, @@ -1590,6 +1594,8 @@ static const struct qmp_phy_cfg sdm845_usb3dpphy_cfg = { }; static const struct qmp_phy_cfg sc8180x_usb3dpphy_cfg = { + .offsets = &qmp_combo_offsets_v3, + .serdes_tbl = sm8150_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl), .tx_tbl = sm8150_usb3_tx_tbl, @@ -1722,6 +1728,8 @@ static const struct qmp_phy_cfg sm6350_usb3dpphy_cfg = { }; static const struct qmp_phy_cfg sm8250_usb3dpphy_cfg = { + .offsets = &qmp_combo_offsets_v3, + .serdes_tbl = sm8150_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl), .tx_tbl = sm8250_usb3_tx_tbl, -- GitLab From 486392f44dd96aeb34bbbc1b119bc5d332f1164f Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 11 Jul 2023 15:09:10 +0300 Subject: [PATCH 0363/3445] phy: qcom-qmp-combo: add qcom,sc7280-qmp-usb3-dp-phy compat entry Add separate device entry for Combo USB+DP QMP PHY on sc7280 platform. Reviewed-by: Neil Armstrong Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230711120916.4165894-5-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index f7b7201d6d9f0..9c3de41ecedb1 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -3514,6 +3514,10 @@ static const struct of_device_id qmp_combo_of_match_table[] = { .compatible = "qcom,sc7180-qmp-usb3-dp-phy", .data = &sc7180_usb3dpphy_cfg, }, + { + .compatible = "qcom,sc7280-qmp-usb3-dp-phy", + .data = &sm8250_usb3dpphy_cfg, + }, { .compatible = "qcom,sc8180x-qmp-usb3-dp-phy", .data = &sc8180x_usb3dpphy_cfg, -- GitLab From 0a41b0c5d97a3758ad102cec469aaa79c7d406b7 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Jul 2023 11:48:50 -0600 Subject: [PATCH 0364/3445] pwm: Explicitly include correct DT includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Reviewed-by: Nobuhiro Iwamatsu Acked-by: Uwe Kleine-König Reviewed-by: Tzung-Bi Shih Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 1 + drivers/pwm/pwm-apple.c | 1 + drivers/pwm/pwm-atmel-hlcdc.c | 1 + drivers/pwm/pwm-atmel-tcb.c | 3 +-- drivers/pwm/pwm-atmel.c | 1 - drivers/pwm/pwm-berlin.c | 1 + drivers/pwm/pwm-cros-ec.c | 1 + drivers/pwm/pwm-fsl-ftm.c | 3 +-- drivers/pwm/pwm-hibvt.c | 2 +- drivers/pwm/pwm-imx1.c | 1 - drivers/pwm/pwm-jz4740.c | 2 +- drivers/pwm/pwm-lp3943.c | 1 + drivers/pwm/pwm-lpc18xx-sct.c | 1 + drivers/pwm/pwm-mediatek.c | 1 - drivers/pwm/pwm-meson.c | 1 - drivers/pwm/pwm-microchip-core.c | 2 +- drivers/pwm/pwm-mtk-disp.c | 1 - drivers/pwm/pwm-pxa.c | 1 + drivers/pwm/pwm-sifive.c | 1 + drivers/pwm/pwm-sl28cpld.c | 1 + drivers/pwm/pwm-sprd.c | 1 + drivers/pwm/pwm-sun4i.c | 1 - drivers/pwm/pwm-sunplus.c | 1 + drivers/pwm/pwm-tegra.c | 1 - drivers/pwm/pwm-tiecap.c | 2 +- drivers/pwm/pwm-tiehrpwm.c | 2 +- drivers/pwm/pwm-visconti.c | 2 +- drivers/pwm/pwm-vt8500.c | 5 +---- 28 files changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 8c798753c0164..11f2f1fd08467 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff --git a/drivers/pwm/pwm-apple.c b/drivers/pwm/pwm-apple.c index a38a62edd7132..8e7d67fb5fbef 100644 --- a/drivers/pwm/pwm-apple.c +++ b/drivers/pwm/pwm-apple.c @@ -12,6 +12,7 @@ * - When APPLE_PWM_CTRL is set to 0, the output is constant low */ +#include #include #include #include diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c index 4d0b859d0ac13..e271d920151e4 100644 --- a/drivers/pwm/pwm-atmel-hlcdc.c +++ b/drivers/pwm/pwm-atmel-hlcdc.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c index 4a116dc44f6e7..563162d660d8e 100644 --- a/drivers/pwm/pwm-atmel-tcb.c +++ b/drivers/pwm/pwm-atmel-tcb.c @@ -19,8 +19,7 @@ #include #include #include -#include -#include +#include #include #include #include diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 5f7d286871cf0..4b243c0e84909 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c index 0c5992a046b20..0971c666afd13 100644 --- a/drivers/pwm/pwm-berlin.c +++ b/drivers/pwm/pwm-berlin.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c index 154ca0f90847b..baaac0c33aa06 100644 --- a/drivers/pwm/pwm-cros-ec.c +++ b/drivers/pwm/pwm-cros-ec.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c index 5caadbd6194e0..b7c6045c5d089 100644 --- a/drivers/pwm/pwm-fsl-ftm.c +++ b/drivers/pwm/pwm-fsl-ftm.c @@ -11,8 +11,7 @@ #include #include #include -#include -#include +#include #include #include #include diff --git a/drivers/pwm/pwm-hibvt.c b/drivers/pwm/pwm-hibvt.c index b95df1a961278..f7ba6fe9a349a 100644 --- a/drivers/pwm/pwm-hibvt.c +++ b/drivers/pwm/pwm-hibvt.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/pwm/pwm-imx1.c b/drivers/pwm/pwm-imx1.c index 1f2eb1c8ff6c9..0651983bed190 100644 --- a/drivers/pwm/pwm-imx1.c +++ b/drivers/pwm/pwm-imx1.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c index 3b7067f6cd0dc..ef1293f2a897e 100644 --- a/drivers/pwm/pwm-jz4740.c +++ b/drivers/pwm/pwm-jz4740.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/pwm/pwm-lp3943.c b/drivers/pwm/pwm-lp3943.c index a39411b87e19b..4b133a17f4be3 100644 --- a/drivers/pwm/pwm-lp3943.c +++ b/drivers/pwm/pwm-lp3943.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c index b9bf5b366f4b1..9ff6311bd4723 100644 --- a/drivers/pwm/pwm-lpc18xx-sct.c +++ b/drivers/pwm/pwm-lpc18xx-sct.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c index 7a51d210a8778..6adb0ed019066 100644 --- a/drivers/pwm/pwm-mediatek.c +++ b/drivers/pwm/pwm-mediatek.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index 22f54db3ae8ea..25519cddc2a9d 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pwm/pwm-microchip-core.c b/drivers/pwm/pwm-microchip-core.c index 8750b57684a90..e7525c98105eb 100644 --- a/drivers/pwm/pwm-microchip-core.c +++ b/drivers/pwm/pwm-microchip-core.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c index 2401b67332417..a83bd6e18b07f 100644 --- a/drivers/pwm/pwm-mtk-disp.c +++ b/drivers/pwm/pwm-mtk-disp.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index 762429d5647fd..c8314053bcb02 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -15,6 +15,7 @@ * input clock (PWMCR_SD is set) and the output is driven to inactive. */ +#include #include #include #include diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c index 25b9b7d9476aa..eabddb7c78208 100644 --- a/drivers/pwm/pwm-sifive.c +++ b/drivers/pwm/pwm-sifive.c @@ -13,6 +13,7 @@ */ #include #include +#include #include #include #include diff --git a/drivers/pwm/pwm-sl28cpld.c b/drivers/pwm/pwm-sl28cpld.c index c789e934671ef..9e42e3a74ad6e 100644 --- a/drivers/pwm/pwm-sl28cpld.c +++ b/drivers/pwm/pwm-sl28cpld.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include diff --git a/drivers/pwm/pwm-sprd.c b/drivers/pwm/pwm-sprd.c index d43a6fa3f4e04..1499c8c1fe375 100644 --- a/drivers/pwm/pwm-sprd.c +++ b/drivers/pwm/pwm-sprd.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index a8790a8fc53e1..c84fcf1a13dc2 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pwm/pwm-sunplus.c b/drivers/pwm/pwm-sunplus.c index d6ebe9f03b354..7705c7b86c3a3 100644 --- a/drivers/pwm/pwm-sunplus.c +++ b/drivers/pwm/pwm-sunplus.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index 5810abf66e2a4..a169a34e07781 100644 --- a/drivers/pwm/pwm-tegra.c +++ b/drivers/pwm/pwm-tegra.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c index 1094499563077..8c94b266c1b2a 100644 --- a/drivers/pwm/pwm-tiecap.c +++ b/drivers/pwm/pwm-tiecap.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include /* ECAP registers and bits definitions */ #define CAP1 0x08 diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index bb3959ace6b48..ecbfd7e954ecb 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include /* EHRPWM registers and bits definitions */ diff --git a/drivers/pwm/pwm-visconti.c b/drivers/pwm/pwm-visconti.c index e3fb79b3e2a7a..7f7591a2384c5 100644 --- a/drivers/pwm/pwm-visconti.c +++ b/drivers/pwm/pwm-visconti.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c index d2c48fd987067..6d46db51daacc 100644 --- a/drivers/pwm/pwm-vt8500.c +++ b/drivers/pwm/pwm-vt8500.c @@ -6,6 +6,7 @@ * Copyright (C) 2010 Alexey Charkov */ +#include #include #include #include @@ -18,10 +19,6 @@ #include -#include -#include -#include - /* * SoC architecture allocates register space for 4 PWMs but only * 2 are currently implemented. -- GitLab From a2f68c7e312f94c8f78740449a88e8d7308ab18d Mon Sep 17 00:00:00 2001 From: Guiting Shen Date: Sun, 16 Jul 2023 10:06:52 +0800 Subject: [PATCH 0365/3445] pwm: atmel: Enable clk when pwm already enabled in bootloader The driver would never call clk_enable() if the PWM channel was already enabled in bootloader which lead to dump the warning message "the PWM clock already disabled" when turning off the PWM channel. Add atmel_pwm_enable_clk_if_on() in probe function to enable clock if the PWM channel was already enabled in bootloader. Signed-off-by: Guiting Shen Reviewed-by: Claudiu Beznea Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel.c | 47 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 4b243c0e84909..03c7810416b84 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -35,7 +35,7 @@ #define PWM_SR 0x0C #define PWM_ISR 0x1C /* Bit field in SR */ -#define PWM_SR_ALL_CH_ON 0x0F +#define PWM_SR_ALL_CH_MASK 0x0F /* The following register is PWM channel related registers */ #define PWM_CH_REG_OFFSET 0x200 @@ -463,6 +463,42 @@ static const struct of_device_id atmel_pwm_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, atmel_pwm_dt_ids); +static int atmel_pwm_enable_clk_if_on(struct atmel_pwm_chip *atmel_pwm, bool on) +{ + unsigned int i, cnt = 0; + unsigned long sr; + int ret = 0; + + sr = atmel_pwm_readl(atmel_pwm, PWM_SR) & PWM_SR_ALL_CH_MASK; + if (!sr) + return 0; + + cnt = bitmap_weight(&sr, atmel_pwm->chip.npwm); + + if (!on) + goto disable_clk; + + for (i = 0; i < cnt; i++) { + ret = clk_enable(atmel_pwm->clk); + if (ret) { + dev_err(atmel_pwm->chip.dev, + "failed to enable clock for pwm %pe\n", + ERR_PTR(ret)); + + cnt = i; + goto disable_clk; + } + } + + return 0; + +disable_clk: + while (cnt--) + clk_disable(atmel_pwm->clk); + + return ret; +} + static int atmel_pwm_probe(struct platform_device *pdev) { struct atmel_pwm_chip *atmel_pwm; @@ -495,16 +531,23 @@ static int atmel_pwm_probe(struct platform_device *pdev) atmel_pwm->chip.ops = &atmel_pwm_ops; atmel_pwm->chip.npwm = 4; + ret = atmel_pwm_enable_clk_if_on(atmel_pwm, true); + if (ret < 0) + goto unprepare_clk; + ret = pwmchip_add(&atmel_pwm->chip); if (ret < 0) { dev_err(&pdev->dev, "failed to add PWM chip %d\n", ret); - goto unprepare_clk; + goto disable_clk; } platform_set_drvdata(pdev, atmel_pwm); return ret; +disable_clk: + atmel_pwm_enable_clk_if_on(atmel_pwm, false); + unprepare_clk: clk_unprepare(atmel_pwm->clk); return ret; -- GitLab From f5a61344ed23e5c5786c399a4c2d0e18af17014a Mon Sep 17 00:00:00 2001 From: Luoyouming Date: Fri, 21 Jul 2023 10:51:45 +0800 Subject: [PATCH 0366/3445] RDMA/hns: Support get XRCD number from firmware Support driver get the num of XRCD from firmware. Signed-off-by: Luoyouming Signed-off-by: Junxian Huang Link: https://lore.kernel.org/r/20230721025146.450831-2-huangjunxian6@hisilicon.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 5 ++--- drivers/infiniband/hw/hns/hns_roce_hw_v2.h | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 8f7eb11066b43..8427e8d319b7f 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -2075,9 +2075,6 @@ static void apply_func_caps(struct hns_roce_dev *hr_dev) caps->qpc_timer_hop_num = HNS_ROCE_HOP_NUM_0; caps->cqc_timer_hop_num = HNS_ROCE_HOP_NUM_0; - caps->num_xrcds = HNS_ROCE_V2_MAX_XRCD_NUM; - caps->reserved_xrcds = HNS_ROCE_V2_RSV_XRCD_NUM; - caps->num_srqwqe_segs = HNS_ROCE_V2_MAX_SRQWQE_SEGS; caps->num_idx_segs = HNS_ROCE_V2_MAX_IDX_SEGS; @@ -2200,6 +2197,7 @@ static int hns_roce_query_caps(struct hns_roce_dev *hr_dev) caps->num_cqs = 1 << hr_reg_read(resp_c, PF_CAPS_C_NUM_CQS); caps->gid_table_len[0] = hr_reg_read(resp_c, PF_CAPS_C_MAX_GID); caps->max_cqes = 1 << hr_reg_read(resp_c, PF_CAPS_C_CQ_DEPTH); + caps->num_xrcds = 1 << hr_reg_read(resp_c, PF_CAPS_C_NUM_XRCDS); caps->num_mtpts = 1 << hr_reg_read(resp_c, PF_CAPS_C_NUM_MRWS); caps->num_qps = 1 << hr_reg_read(resp_c, PF_CAPS_C_NUM_QPS); caps->max_qp_init_rdma = hr_reg_read(resp_c, PF_CAPS_C_MAX_ORD); @@ -2220,6 +2218,7 @@ static int hns_roce_query_caps(struct hns_roce_dev *hr_dev) caps->reserved_mrws = hr_reg_read(resp_e, PF_CAPS_E_RSV_MRWS); caps->chunk_sz = 1 << hr_reg_read(resp_e, PF_CAPS_E_CHUNK_SIZE_SHIFT); caps->reserved_cqs = hr_reg_read(resp_e, PF_CAPS_E_RSV_CQS); + caps->reserved_xrcds = hr_reg_read(resp_e, PF_CAPS_E_RSV_XRCDS); caps->reserved_srqs = hr_reg_read(resp_e, PF_CAPS_E_RSV_SRQS); caps->reserved_lkey = hr_reg_read(resp_e, PF_CAPS_E_RSV_LKEYS); diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h index 7033eae2407c5..2b87f0cf06ec8 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h @@ -42,7 +42,6 @@ #define HNS_ROCE_V2_MAX_SRQWQE_SEGS 0x1000000 #define HNS_ROCE_V2_MAX_IDX_SEGS 0x1000000 #define HNS_ROCE_V2_MAX_XRCD_NUM 0x1000000 -#define HNS_ROCE_V2_RSV_XRCD_NUM 0 #define HNS_ROCE_V2_QP_ACK_TIMEOUT_OFS_HIP08 10 @@ -1202,6 +1201,7 @@ struct hns_roce_query_pf_caps_c { #define PF_CAPS_C_NUM_CQS PF_CAPS_C_FIELD_LOC(51, 32) #define PF_CAPS_C_MAX_GID PF_CAPS_C_FIELD_LOC(60, 52) #define PF_CAPS_C_CQ_DEPTH PF_CAPS_C_FIELD_LOC(86, 64) +#define PF_CAPS_C_NUM_XRCDS PF_CAPS_C_FIELD_LOC(91, 87) #define PF_CAPS_C_NUM_MRWS PF_CAPS_C_FIELD_LOC(115, 96) #define PF_CAPS_C_NUM_QPS PF_CAPS_C_FIELD_LOC(147, 128) #define PF_CAPS_C_MAX_ORD PF_CAPS_C_FIELD_LOC(155, 148) @@ -1260,6 +1260,7 @@ struct hns_roce_query_pf_caps_e { #define PF_CAPS_E_RSV_MRWS PF_CAPS_E_FIELD_LOC(19, 0) #define PF_CAPS_E_CHUNK_SIZE_SHIFT PF_CAPS_E_FIELD_LOC(31, 20) #define PF_CAPS_E_RSV_CQS PF_CAPS_E_FIELD_LOC(51, 32) +#define PF_CAPS_E_RSV_XRCDS PF_CAPS_E_FIELD_LOC(63, 52) #define PF_CAPS_E_RSV_SRQS PF_CAPS_E_FIELD_LOC(83, 64) #define PF_CAPS_E_RSV_LKEYS PF_CAPS_E_FIELD_LOC(115, 96) -- GitLab From 0b5eed06832c87275ee67f69a943d811b1fe066d Mon Sep 17 00:00:00 2001 From: Junxian Huang Date: Fri, 21 Jul 2023 10:51:46 +0800 Subject: [PATCH 0367/3445] RDMA/hns: Remove VF extend configuration Remove VF extend configuration since the relative registers are configured in firmware currently. Signed-off-by: Junxian Huang Link: https://lore.kernel.org/r/20230721025146.450831-3-huangjunxian6@hisilicon.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/hns/hns_roce_device.h | 1 - drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 84 +++------------------ drivers/infiniband/hw/hns/hns_roce_hw_v2.h | 10 --- 3 files changed, 10 insertions(+), 85 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 84239b907de2a..6084c16490006 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -714,7 +714,6 @@ struct hns_roce_caps { u32 max_rq_sg; u32 rsv0; u32 num_qps; - u32 num_pi_qps; u32 reserved_qps; u32 num_srqs; u32 max_wqes; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 8427e8d319b7f..30451cef5376e 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -1680,29 +1680,6 @@ static int load_func_res_caps(struct hns_roce_dev *hr_dev, bool is_vf) return 0; } -static int load_ext_cfg_caps(struct hns_roce_dev *hr_dev, bool is_vf) -{ - struct hns_roce_cmq_desc desc; - struct hns_roce_cmq_req *req = (struct hns_roce_cmq_req *)desc.data; - struct hns_roce_caps *caps = &hr_dev->caps; - u32 func_num, qp_num; - int ret; - - hns_roce_cmq_setup_basic_desc(&desc, HNS_ROCE_OPC_EXT_CFG, true); - ret = hns_roce_cmq_send(hr_dev, &desc, 1); - if (ret) - return ret; - - func_num = is_vf ? 1 : max_t(u32, 1, hr_dev->func_num); - qp_num = hr_reg_read(req, EXT_CFG_QP_PI_NUM) / func_num; - caps->num_pi_qps = round_down(qp_num, HNS_ROCE_QP_BANK_NUM); - - qp_num = hr_reg_read(req, EXT_CFG_QP_NUM) / func_num; - caps->num_qps = round_down(qp_num, HNS_ROCE_QP_BANK_NUM); - - return 0; -} - static int load_pf_timer_res_caps(struct hns_roce_dev *hr_dev) { struct hns_roce_cmq_desc desc; @@ -1723,50 +1700,37 @@ static int load_pf_timer_res_caps(struct hns_roce_dev *hr_dev) return 0; } -static int query_func_resource_caps(struct hns_roce_dev *hr_dev, bool is_vf) +static int hns_roce_query_pf_resource(struct hns_roce_dev *hr_dev) { struct device *dev = hr_dev->dev; int ret; - ret = load_func_res_caps(hr_dev, is_vf); + ret = load_func_res_caps(hr_dev, false); if (ret) { - dev_err(dev, "failed to load res caps, ret = %d (%s).\n", ret, - is_vf ? "vf" : "pf"); + dev_err(dev, "failed to load pf res caps, ret = %d.\n", ret); return ret; } - if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP09) { - ret = load_ext_cfg_caps(hr_dev, is_vf); - if (ret) - dev_err(dev, "failed to load ext cfg, ret = %d (%s).\n", - ret, is_vf ? "vf" : "pf"); - } + ret = load_pf_timer_res_caps(hr_dev); + if (ret) + dev_err(dev, "failed to load pf timer resource, ret = %d.\n", + ret); return ret; } -static int hns_roce_query_pf_resource(struct hns_roce_dev *hr_dev) +static int hns_roce_query_vf_resource(struct hns_roce_dev *hr_dev) { struct device *dev = hr_dev->dev; int ret; - ret = query_func_resource_caps(hr_dev, false); + ret = load_func_res_caps(hr_dev, true); if (ret) - return ret; - - ret = load_pf_timer_res_caps(hr_dev); - if (ret) - dev_err(dev, "failed to load pf timer resource, ret = %d.\n", - ret); + dev_err(dev, "failed to load vf res caps, ret = %d.\n", ret); return ret; } -static int hns_roce_query_vf_resource(struct hns_roce_dev *hr_dev) -{ - return query_func_resource_caps(hr_dev, true); -} - static int __hns_roce_set_vf_switch_param(struct hns_roce_dev *hr_dev, u32 vf_id) { @@ -1849,24 +1813,6 @@ static int config_vf_hem_resource(struct hns_roce_dev *hr_dev, int vf_id) return hns_roce_cmq_send(hr_dev, desc, 2); } -static int config_vf_ext_resource(struct hns_roce_dev *hr_dev, u32 vf_id) -{ - struct hns_roce_cmq_desc desc; - struct hns_roce_cmq_req *req = (struct hns_roce_cmq_req *)desc.data; - struct hns_roce_caps *caps = &hr_dev->caps; - - hns_roce_cmq_setup_basic_desc(&desc, HNS_ROCE_OPC_EXT_CFG, false); - - hr_reg_write(req, EXT_CFG_VF_ID, vf_id); - - hr_reg_write(req, EXT_CFG_QP_PI_NUM, caps->num_pi_qps); - hr_reg_write(req, EXT_CFG_QP_PI_IDX, vf_id * caps->num_pi_qps); - hr_reg_write(req, EXT_CFG_QP_NUM, caps->num_qps); - hr_reg_write(req, EXT_CFG_QP_IDX, vf_id * caps->num_qps); - - return hns_roce_cmq_send(hr_dev, &desc, 1); -} - static int hns_roce_alloc_vf_resource(struct hns_roce_dev *hr_dev) { u32 func_num = max_t(u32, 1, hr_dev->func_num); @@ -1881,16 +1827,6 @@ static int hns_roce_alloc_vf_resource(struct hns_roce_dev *hr_dev) vf_id, ret); return ret; } - - if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP09) { - ret = config_vf_ext_resource(hr_dev, vf_id); - if (ret) { - dev_err(hr_dev->dev, - "failed to config vf-%u ext res, ret = %d.\n", - vf_id, ret); - return ret; - } - } } return 0; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h index 2b87f0cf06ec8..d9693f6cc802f 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h @@ -219,7 +219,6 @@ enum hns_roce_opcode_type { HNS_ROCE_OPC_QUERY_VF_RES = 0x850e, HNS_ROCE_OPC_CFG_GMV_TBL = 0x850f, HNS_ROCE_OPC_CFG_GMV_BT = 0x8510, - HNS_ROCE_OPC_EXT_CFG = 0x8512, HNS_ROCE_QUERY_RAM_ECC = 0x8513, HNS_SWITCH_PARAMETER_CFG = 0x1033, }; @@ -956,15 +955,6 @@ struct hns_roce_func_clear { #define HNS_ROCE_V2_READ_FUNC_CLEAR_FLAG_INTERVAL 40 #define HNS_ROCE_V2_READ_FUNC_CLEAR_FLAG_FAIL_WAIT 20 -/* Fields of HNS_ROCE_OPC_EXT_CFG */ -#define EXT_CFG_VF_ID CMQ_REQ_FIELD_LOC(31, 0) -#define EXT_CFG_QP_PI_IDX CMQ_REQ_FIELD_LOC(45, 32) -#define EXT_CFG_QP_PI_NUM CMQ_REQ_FIELD_LOC(63, 48) -#define EXT_CFG_QP_NUM CMQ_REQ_FIELD_LOC(87, 64) -#define EXT_CFG_QP_IDX CMQ_REQ_FIELD_LOC(119, 96) -#define EXT_CFG_LLM_IDX CMQ_REQ_FIELD_LOC(139, 128) -#define EXT_CFG_LLM_NUM CMQ_REQ_FIELD_LOC(156, 144) - #define CFG_LLM_A_BA_L CMQ_REQ_FIELD_LOC(31, 0) #define CFG_LLM_A_BA_H CMQ_REQ_FIELD_LOC(63, 32) #define CFG_LLM_A_DEPTH CMQ_REQ_FIELD_LOC(76, 64) -- GitLab From 24b1b5d85c1c1e1c0eb7b6d7b6986ecb6c80041d Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 22 Jul 2023 18:47:24 +0200 Subject: [PATCH 0368/3445] IB/hfi1: Use struct_size() Use struct_size() instead of hand-writing it, when allocating a structure with a flex array. This is less verbose, more robust and more informative. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/f4618a67d5ae0a30eb3f2b4558c8cc790feed79a.1690044376.git.christophe.jaillet@wanadoo.fr Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/hfi1/pio.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/pio.c b/drivers/infiniband/hw/hfi1/pio.c index 62e7dc9bea7bd..dfea53e0fdeb8 100644 --- a/drivers/infiniband/hw/hfi1/pio.c +++ b/drivers/infiniband/hw/hfi1/pio.c @@ -1893,9 +1893,7 @@ int pio_map_init(struct hfi1_devdata *dd, u8 port, u8 num_vls, u8 *vl_scontexts) vl_scontexts[i] = sc_per_vl + (extra > 0 ? 1 : 0); } /* build new map */ - newmap = kzalloc(sizeof(*newmap) + - roundup_pow_of_two(num_vls) * - sizeof(struct pio_map_elem *), + newmap = kzalloc(struct_size(newmap, map, roundup_pow_of_two(num_vls)), GFP_KERNEL); if (!newmap) goto bail; @@ -1910,9 +1908,8 @@ int pio_map_init(struct hfi1_devdata *dd, u8 port, u8 num_vls, u8 *vl_scontexts) int sz = roundup_pow_of_two(vl_scontexts[i]); /* only allocate once */ - newmap->map[i] = kzalloc(sizeof(*newmap->map[i]) + - sz * sizeof(struct - send_context *), + newmap->map[i] = kzalloc(struct_size(newmap->map[i], + ksc, sz), GFP_KERNEL); if (!newmap->map[i]) goto bail; -- GitLab From c40e60f00caf18bc382215c79651777eb40f5f9d Mon Sep 17 00:00:00 2001 From: "Borislav Petkov (AMD)" Date: Wed, 5 Jul 2023 00:19:51 +0200 Subject: [PATCH 0369/3445] kbuild: Enable -Wenum-conversion by default This diagnostic checks whether there is a type mismatch when converting enums (assign an enum of type A to an enum of type B, for example) and it caught a legit issue recently. The reason it didn't show is because that warning is enabled only with -Wextra with GCC. Clang, however, enables it by default. GCC folks were considering enabling it by default but it was too noisy back then: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78736 Now that due to clang all those warnings have been fixed, enable it with GCC too. allmodconfig tests done with: x86, arm{,64}, powerpc{,64}, riscv crossbuilds. Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Nathan Chancellor Signed-off-by: Masahiro Yamada --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 22e392649b025..d36e5361810fa 100644 --- a/Makefile +++ b/Makefile @@ -1090,6 +1090,9 @@ KBUILD_CFLAGS += $(call cc-option,-Werror=incompatible-pointer-types) # Require designated initializers for all marked structures KBUILD_CFLAGS += $(call cc-option,-Werror=designated-init) +# Warn if there is an enum types mismatch +KBUILD_CFLAGS += $(call cc-option,-Wenum-conversion) + # change __FILE__ to the relative path from the srctree KBUILD_CPPFLAGS += $(call cc-option,-fmacro-prefix-map=$(srctree)/=) -- GitLab From 481461f5109919babbb393d6f68002936b8e2493 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 16 Jul 2023 19:15:54 +0900 Subject: [PATCH 0370/3445] linux/export.h: make independent of CONFIG_MODULES Currently, all files with EXPORT_SYMBOL() are rebuilt when CONFIG_MODULES is flipped due to depending on CONFIG_MODULES. Now that modpost can make a final decision about export symbols, does not need to make EXPORT_SYMBOL() no-op. Instead, modpost can skip emitting KSYMTAB when CONFIG_MODULES is unset. This commit will reduce the number of recompilation when CONFIG_MODULES is toggled. Signed-off-by: Masahiro Yamada --- include/linux/export.h | 4 ++-- scripts/Makefile.modpost | 1 + scripts/mod/modpost.c | 8 ++++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/linux/export.h b/include/linux/export.h index beed8387e0a44..9911508a9604f 100644 --- a/include/linux/export.h +++ b/include/linux/export.h @@ -50,7 +50,7 @@ extern struct module __this_module; __EXPORT_SYMBOL_REF(sym) ASM_NL \ .previous -#if !defined(CONFIG_MODULES) || defined(__DISABLE_EXPORTS) +#if defined(__DISABLE_EXPORTS) /* * Allow symbol exports to be disabled completely so that C code may @@ -75,7 +75,7 @@ extern struct module __this_module; __ADDRESSABLE(sym) \ asm(__stringify(___EXPORT_SYMBOL(sym, license, ns))) -#endif /* CONFIG_MODULES */ +#endif #ifdef DEFAULT_SYMBOL_NAMESPACE #define _EXPORT_SYMBOL(sym, license) __EXPORT_SYMBOL(sym, license, __stringify(DEFAULT_SYMBOL_NAMESPACE)) diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 39472e834b634..739402f455097 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -41,6 +41,7 @@ include $(srctree)/scripts/Kbuild.include MODPOST = scripts/mod/modpost modpost-args = \ + $(if $(CONFIG_MODULES),-M) \ $(if $(CONFIG_MODVERSIONS),-m) \ $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a) \ $(if $(CONFIG_SECTION_MISMATCH_WARN_ONLY),,-E) \ diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index b29b29707f104..8227641dd087b 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -24,6 +24,7 @@ #include "../../include/linux/license.h" #include "../../include/linux/module_symbol.h" +static bool module_enabled; /* Are we using CONFIG_MODVERSIONS? */ static bool modversions; /* Is CONFIG_MODULE_SRCVERSION_ALL set? */ @@ -1242,7 +1243,7 @@ static void check_section_mismatch(struct module *mod, struct elf_info *elf, const char *tosec = sec_name(elf, get_secindex(elf, sym)); const struct sectioncheck *mismatch; - if (elf->export_symbol_secndx == fsecndx) { + if (module_enabled && elf->export_symbol_secndx == fsecndx) { check_export_symbol(mod, elf, faddr, tosec, sym); return; } @@ -2272,7 +2273,7 @@ int main(int argc, char **argv) LIST_HEAD(dump_lists); struct dump_list *dl, *dl2; - while ((opt = getopt(argc, argv, "ei:mnT:to:au:WwENd:")) != -1) { + while ((opt = getopt(argc, argv, "ei:MmnT:to:au:WwENd:")) != -1) { switch (opt) { case 'e': external_module = true; @@ -2282,6 +2283,9 @@ int main(int argc, char **argv) dl->file = optarg; list_add_tail(&dl->list, &dump_lists); break; + case 'M': + module_enabled = true; + break; case 'm': modversions = true; break; -- GitLab From e14f1242a8be413846360b295102abd4c62848ad Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 16 Jul 2023 13:55:07 +0900 Subject: [PATCH 0371/3445] kconfig: menuconfig: simplify global jump key assignment Commit 95ac9b3b585d ("menuconfig: Assign jump keys per-page instead of globally") injected a lot of hacks to the bottom of the textbox infrastructure. I reverted many of them without changing the behavior. (almost) Now, the key markers are inserted when constructing the search result instead of updating the text buffer on-the-fly. The buffer passed to the textbox got back to a constant string. The ugly casts from (const char *) to (char *) went away. A disadvantage is that the same key numbers might be displayed multiple times in the dialog if you use a huge window (but I believe it is unlikely to happen). Signed-off-by: Masahiro Yamada Reviewed-by: Jesse Taube --- scripts/kconfig/lkc.h | 1 + scripts/kconfig/lxdialog/dialog.h | 10 ++-- scripts/kconfig/lxdialog/textbox.c | 68 +++++++++-------------- scripts/kconfig/mconf.c | 86 +++++++++++++++++------------- scripts/kconfig/menu.c | 22 ++++++-- 5 files changed, 97 insertions(+), 90 deletions(-) diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index e7118d62a45fc..471a59acecec6 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -101,6 +101,7 @@ const char *menu_get_prompt(struct menu *menu); struct menu *menu_get_parent_menu(struct menu *menu); bool menu_has_help(struct menu *menu); const char *menu_get_help(struct menu *menu); +int get_jump_key_char(void); struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head); void menu_get_ext_help(struct menu *menu, struct gstr *help); diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h index 347daf25fdc8b..a501abf9fa313 100644 --- a/scripts/kconfig/lxdialog/dialog.h +++ b/scripts/kconfig/lxdialog/dialog.h @@ -196,13 +196,9 @@ int first_alpha(const char *string, const char *exempt); int dialog_yesno(const char *title, const char *prompt, int height, int width); int dialog_msgbox(const char *title, const char *prompt, int height, int width, int pause); - - -typedef void (*update_text_fn)(char *buf, size_t start, size_t end, void - *_data); -int dialog_textbox(const char *title, char *tbuf, int initial_height, - int initial_width, int *keys, int *_vscroll, int *_hscroll, - update_text_fn update_text, void *data); +int dialog_textbox(const char *title, const char *tbuf, int initial_height, + int initial_width, int *_vscroll, int *_hscroll, + int (*extra_key_cb)(int, size_t, size_t, void *), void *data); int dialog_menu(const char *title, const char *prompt, const void *selected, int *s_scroll); int dialog_checklist(const char *title, const char *prompt, int height, diff --git a/scripts/kconfig/lxdialog/textbox.c b/scripts/kconfig/lxdialog/textbox.c index bc4d4fb1dc750..058ed0e5bbd54 100644 --- a/scripts/kconfig/lxdialog/textbox.c +++ b/scripts/kconfig/lxdialog/textbox.c @@ -10,8 +10,8 @@ static int hscroll; static int begin_reached, end_reached, page_length; -static char *buf; -static char *page; +static const char *buf, *page; +static size_t start, end; /* * Go back 'n' lines in text. Called by dialog_textbox(). @@ -98,21 +98,10 @@ static void print_line(WINDOW *win, int row, int width) /* * Print a new page of text. */ -static void print_page(WINDOW *win, int height, int width, update_text_fn - update_text, void *data) +static void print_page(WINDOW *win, int height, int width) { int i, passed_end = 0; - if (update_text) { - char *end; - - for (i = 0; i < height; i++) - get_line(); - end = page; - back_lines(height); - update_text(buf, page - buf, end - buf, data); - } - page_length = 0; for (i = 0; i < height; i++) { print_line(win, i, width); @@ -142,24 +131,26 @@ static void print_position(WINDOW *win) * refresh window content */ static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw, - int cur_y, int cur_x, update_text_fn update_text, - void *data) + int cur_y, int cur_x) { - print_page(box, boxh, boxw, update_text, data); + start = page - buf; + + print_page(box, boxh, boxw); print_position(dialog); wmove(dialog, cur_y, cur_x); /* Restore cursor position */ wrefresh(dialog); + + end = page - buf; } /* * Display text from a file in a dialog box. * * keys is a null-terminated array - * update_text() may not add or remove any '\n' or '\0' in tbuf */ -int dialog_textbox(const char *title, char *tbuf, int initial_height, - int initial_width, int *keys, int *_vscroll, int *_hscroll, - update_text_fn update_text, void *data) +int dialog_textbox(const char *title, const char *tbuf, int initial_height, + int initial_width, int *_vscroll, int *_hscroll, + int (*extra_key_cb)(int, size_t, size_t, void *), void *data) { int i, x, y, cur_x, cur_y, key = 0; int height, width, boxh, boxw; @@ -239,8 +230,7 @@ do_resize: /* Print first page of text */ attr_clear(box, boxh, boxw, dlg.dialog.atr); - refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x, update_text, - data); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); while (!done) { key = wgetch(dialog); @@ -259,8 +249,7 @@ do_resize: begin_reached = 1; page = buf; refresh_text_box(dialog, box, boxh, boxw, - cur_y, cur_x, update_text, - data); + cur_y, cur_x); } break; case 'G': /* Last page */ @@ -270,8 +259,7 @@ do_resize: /* point to last char in buf */ page = buf + strlen(buf); back_lines(boxh); - refresh_text_box(dialog, box, boxh, boxw, cur_y, - cur_x, update_text, data); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); break; case 'K': /* Previous line */ case 'k': @@ -280,8 +268,7 @@ do_resize: break; back_lines(page_length + 1); - refresh_text_box(dialog, box, boxh, boxw, cur_y, - cur_x, update_text, data); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); break; case 'B': /* Previous page */ case 'b': @@ -290,8 +277,7 @@ do_resize: if (begin_reached) break; back_lines(page_length + boxh); - refresh_text_box(dialog, box, boxh, boxw, cur_y, - cur_x, update_text, data); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); break; case 'J': /* Next line */ case 'j': @@ -300,8 +286,7 @@ do_resize: break; back_lines(page_length - 1); - refresh_text_box(dialog, box, boxh, boxw, cur_y, - cur_x, update_text, data); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); break; case KEY_NPAGE: /* Next page */ case ' ': @@ -310,8 +295,7 @@ do_resize: break; begin_reached = 0; - refresh_text_box(dialog, box, boxh, boxw, cur_y, - cur_x, update_text, data); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); break; case '0': /* Beginning of line */ case 'H': /* Scroll left */ @@ -326,8 +310,7 @@ do_resize: hscroll--; /* Reprint current page to scroll horizontally */ back_lines(page_length); - refresh_text_box(dialog, box, boxh, boxw, cur_y, - cur_x, update_text, data); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); break; case 'L': /* Scroll right */ case 'l': @@ -337,8 +320,7 @@ do_resize: hscroll++; /* Reprint current page to scroll horizontally */ back_lines(page_length); - refresh_text_box(dialog, box, boxh, boxw, cur_y, - cur_x, update_text, data); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); break; case KEY_ESC: if (on_key_esc(dialog) == KEY_ESC) @@ -351,11 +333,9 @@ do_resize: on_key_resize(); goto do_resize; default: - for (i = 0; keys[i]; i++) { - if (key == keys[i]) { - done = true; - break; - } + if (extra_key_cb && extra_key_cb(key, start, end, data)) { + done = true; + break; } } } diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index 53d8834d12fe0..15b88921fe6a5 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -288,6 +288,7 @@ static int single_menu_mode; static int show_all_options; static int save_and_exit; static int silent; +static int jump_key_char; static void conf(struct menu *menu, struct menu *active_menu); @@ -348,19 +349,19 @@ static void reset_subtitle(void) set_dialog_subtitles(subtitles); } -static int show_textbox_ext(const char *title, char *text, int r, int c, int - *keys, int *vscroll, int *hscroll, update_text_fn - update_text, void *data) +static int show_textbox_ext(const char *title, const char *text, int r, int c, + int *vscroll, int *hscroll, + int (*extra_key_cb)(int, size_t, size_t, void *), + void *data) { dialog_clear(); - return dialog_textbox(title, text, r, c, keys, vscroll, hscroll, - update_text, data); + return dialog_textbox(title, text, r, c, vscroll, hscroll, + extra_key_cb, data); } static void show_textbox(const char *title, const char *text, int r, int c) { - show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL, - NULL, NULL); + show_textbox_ext(title, text, r, c, NULL, NULL, NULL, NULL); } static void show_helptext(const char *title, const char *text) @@ -381,35 +382,51 @@ static void show_help(struct menu *menu) struct search_data { struct list_head *head; - struct menu **targets; - int *keys; + struct menu *target; }; -static void update_text(char *buf, size_t start, size_t end, void *_data) +static int next_jump_key(int key) +{ + if (key < '1' || key > '9') + return '1'; + + key++; + + if (key > '9') + key = '1'; + + return key; +} + +static int handle_search_keys(int key, size_t start, size_t end, void *_data) { struct search_data *data = _data; struct jump_key *pos; - int k = 0; - list_for_each_entry(pos, data->head, entries) { - if (pos->offset >= start && pos->offset < end) { - char header[4]; + if (key < '1' || key > '9') + return 0; - if (k < JUMP_NB) { - int key = '0' + (pos->index % JUMP_NB) + 1; + list_for_each_entry(pos, data->head, entries) { + if (pos->offset < start) + continue; - sprintf(header, "(%c)", key); - data->keys[k] = key; - data->targets[k] = pos->target; - k++; - } else { - sprintf(header, " "); - } + if (pos->offset >= end) + break; - memcpy(buf + pos->offset, header, sizeof(header) - 1); + if (key == '1' + (pos->index % JUMP_NB)) { + data->target = pos->target; + return 1; } } - data->keys[k] = 0; + + return 0; +} + +int get_jump_key_char(void) +{ + jump_key_char = next_jump_key(jump_key_char); + + return jump_key_char; } static void search_conf(void) @@ -456,26 +473,23 @@ again: sym_arr = sym_re_search(dialog_input); do { LIST_HEAD(head); - struct menu *targets[JUMP_NB]; - int keys[JUMP_NB + 1], i; struct search_data data = { .head = &head, - .targets = targets, - .keys = keys, }; struct jump_key *pos, *tmp; + jump_key_char = 0; res = get_relations_str(sym_arr, &head); set_subtitle(); dres = show_textbox_ext("Search Results", str_get(&res), 0, 0, - keys, &vscroll, &hscroll, &update_text, - &data); + &vscroll, &hscroll, + handle_search_keys, &data); again = false; - for (i = 0; i < JUMP_NB && keys[i]; i++) - if (dres == keys[i]) { - conf(targets[i]->parent, targets[i]); - again = true; - } + if (dres >= '1' && dres <= '9') { + assert(data.target != NULL); + conf(data.target->parent, data.target); + again = true; + } str_free(&res); list_for_each_entry_safe(pos, tmp, &head, entries) free(pos); diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index b90fff833588a..d2f0a8efabb55 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -701,6 +701,11 @@ static void get_dep_str(struct gstr *r, struct expr *expr, const char *prefix) } } +int __attribute__((weak)) get_jump_key_char(void) +{ + return -1; +} + static void get_prompt_str(struct gstr *r, struct property *prop, struct list_head *head) { @@ -743,11 +748,22 @@ static void get_prompt_str(struct gstr *r, struct property *prop, } str_printf(r, " Location:\n"); - for (j = 4; --i >= 0; j += 2) { + for (j = 0; --i >= 0; j++) { + int jk = -1; + int indent = 2 * j + 4; + menu = submenu[i]; - if (jump && menu == location) + if (jump && menu == location) { jump->offset = strlen(r->s); - str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu)); + jk = get_jump_key_char(); + } + + if (jk >= 0) { + str_printf(r, "(%c)", jk); + indent -= 3; + } + + str_printf(r, "%*c-> %s", indent, ' ', menu_get_prompt(menu)); if (menu->sym) { str_printf(r, " (%s [=%s])", menu->sym->name ? menu->sym->name : "", -- GitLab From 356f0cb7efd9563112f18a2c8647ceb6d9f2ccef Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 16 Jul 2023 13:55:08 +0900 Subject: [PATCH 0372/3445] kconfig: menuconfig: remove jump_key::index You do not need to remember the index of each jump key because you can count it up after a key is pressed. Signed-off-by: Masahiro Yamada Reviewed-by: Jesse Taube --- scripts/kconfig/expr.h | 1 - scripts/kconfig/mconf.c | 7 ++++--- scripts/kconfig/menu.c | 8 -------- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index 9c9caca5bd5f2..4a9a23b1b7e1f 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -275,7 +275,6 @@ struct jump_key { struct list_head entries; size_t offset; struct menu *target; - int index; }; extern struct file *file_list; diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index 15b88921fe6a5..eccc87a441e71 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -22,8 +22,6 @@ #include "lkc.h" #include "lxdialog/dialog.h" -#define JUMP_NB 9 - static const char mconf_readme[] = "Overview\n" "--------\n" @@ -402,18 +400,21 @@ static int handle_search_keys(int key, size_t start, size_t end, void *_data) { struct search_data *data = _data; struct jump_key *pos; + int index = 0; if (key < '1' || key > '9') return 0; list_for_each_entry(pos, data->head, entries) { + index = next_jump_key(index); + if (pos->offset < start) continue; if (pos->offset >= end) break; - if (key == '1' + (pos->index % JUMP_NB)) { + if (key == index) { data->target = pos->target; return 1; } diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index d2f0a8efabb55..61c442d84aef4 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -735,15 +735,7 @@ static void get_prompt_str(struct gstr *r, struct property *prop, } if (head && location) { jump = xmalloc(sizeof(struct jump_key)); - jump->target = location; - - if (list_empty(head)) - jump->index = 0; - else - jump->index = list_entry(head->prev, struct jump_key, - entries)->index + 1; - list_add_tail(&jump->entries, head); } -- GitLab From 4d15c9fa058e6dee09324cfc93f48858d4296019 Mon Sep 17 00:00:00 2001 From: Michal Suchanek Date: Tue, 18 Jul 2023 18:58:43 +0200 Subject: [PATCH 0373/3445] Revert "kbuild: Hack for depmod not handling X.Y versions" Remove hack for ancient version of module-init-tools that was added in Linux 3.0. Since then module-init-tools was replaced with kmod. This hack adds an additional indirection, and causes confusing errors to be printed when depmod fails. Reverts commit 8fc62e594253 ("kbuild: Do not write to builddir in modules_install") Reverts commit bfe5424a8b31 ("kbuild: Hack for depmod not handling X.Y versions") Link: https://lore.kernel.org/linux-modules/CAK7LNAQMs3QBYfWcLkmOQdbbq7cj=7wWbK=AWhdTC2rAsKHXzQ@mail.gmail.com/ Signed-off-by: Michal Suchanek Signed-off-by: Masahiro Yamada --- scripts/depmod.sh | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/scripts/depmod.sh b/scripts/depmod.sh index 3643b4f896ede..fca689ba4f211 100755 --- a/scripts/depmod.sh +++ b/scripts/depmod.sh @@ -23,33 +23,8 @@ if [ -z $(command -v $DEPMOD) ]; then exit 0 fi -# older versions of depmod require the version string to start with three -# numbers, so we cheat with a symlink here -depmod_hack_needed=true -tmp_dir=$(mktemp -d ${TMPDIR:-/tmp}/depmod.XXXXXX) -mkdir -p "$tmp_dir/lib/modules/$KERNELRELEASE" -if "$DEPMOD" -b "$tmp_dir" $KERNELRELEASE 2>/dev/null; then - if test -e "$tmp_dir/lib/modules/$KERNELRELEASE/modules.dep" -o \ - -e "$tmp_dir/lib/modules/$KERNELRELEASE/modules.dep.bin"; then - depmod_hack_needed=false - fi -fi -rm -rf "$tmp_dir" -if $depmod_hack_needed; then - symlink="$INSTALL_MOD_PATH/lib/modules/99.98.$KERNELRELEASE" - ln -s "$KERNELRELEASE" "$symlink" - KERNELRELEASE=99.98.$KERNELRELEASE -fi - set -- -ae -F System.map if test -n "$INSTALL_MOD_PATH"; then set -- "$@" -b "$INSTALL_MOD_PATH" fi -"$DEPMOD" "$@" "$KERNELRELEASE" -ret=$? - -if $depmod_hack_needed; then - rm -f "$symlink" -fi - -exit $ret +exec "$DEPMOD" "$@" "$KERNELRELEASE" -- GitLab From 233046a2afd12a4f699305b92ee634eebf1e4f31 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 22 Jul 2023 13:47:48 +0900 Subject: [PATCH 0374/3445] kbuild: rpm-pkg: define _arch conditionally Commit 3089b2be0cce ("kbuild: rpm-pkg: fix build error when _arch is undefined") does not work as intended; _arch is always defined as $UTS_MACHINE. The intention was to define _arch to $UTS_MACHINE only when it is not defined. Fixes: 3089b2be0cce ("kbuild: rpm-pkg: fix build error when _arch is undefined") Signed-off-by: Masahiro Yamada --- scripts/package/mkspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/package/mkspec b/scripts/package/mkspec index 8049f0e2c110f..c9299f9c1f3e4 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -57,7 +57,7 @@ $S BuildRequires: gcc make openssl openssl-devel perl python3 rsync # $UTS_MACHINE as a fallback of _arch in case # /usr/lib/rpm/platform/*/macros was not included. - %define _arch %{?_arch:$UTS_MACHINE} + %{!?_arch: %define _arch $UTS_MACHINE} %define __spec_install_post /usr/lib/rpm/brp-compress || : %define debug_package %{nil} -- GitLab From 61eca933d0a63f0889df604df6bb38938f3c7cad Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 22 Jul 2023 13:47:49 +0900 Subject: [PATCH 0375/3445] kbuild: rpm-pkg: remove unneeded '-f $srctree/Makefile' in spec file This is unneeded because the Makefile in the output directory wraps the top-level Makefile in the srctree. Just run $MAKE irrespective of the build location. Signed-off-by: Masahiro Yamada --- scripts/package/mkspec | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/package/mkspec b/scripts/package/mkspec index c9299f9c1f3e4..a83b17b4a0d96 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -12,7 +12,6 @@ # how we were called determines which rpms we build and how we build them if [ "$1" = prebuilt ]; then S=DEL - MAKE="$MAKE -f $srctree/Makefile" else S= -- GitLab From 192868258d2c9eb421228e4d65c4b09b838e7d93 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 22 Jul 2023 13:47:50 +0900 Subject: [PATCH 0376/3445] kbuild: rpm-pkg: do not hard-code $MAKE in spec file Currently, $MAKE will expand to the GNU Make program that created the source RPM. This is problematic if you carry it to a different build host to run 'rpmbuild' there. Consider this command: $ /path/to/my/custom/make srcrpm-pkg The spec file in the SRPM will record '/path/to/my/custom/make', which exists only on that build environment. To create a portable SRPM, the spec file should avoid hard-coding $MAKE. Signed-off-by: Masahiro Yamada --- scripts/Makefile.package | 5 +++-- scripts/package/mkspec | 12 +++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/scripts/Makefile.package b/scripts/Makefile.package index 92dbc889bd7c0..e9217e997c683 100644 --- a/scripts/Makefile.package +++ b/scripts/Makefile.package @@ -72,7 +72,7 @@ PHONY += rpm-pkg rpm-pkg: srpm = $(shell rpmspec --srpm --query --queryformat='%{name}-%{VERSION}-%{RELEASE}.src.rpm' kernel.spec) rpm-pkg: srcrpm-pkg +rpmbuild $(RPMOPTS) --target $(UTS_MACHINE)-linux -rb $(srpm) \ - --define='_smp_mflags %{nil}' + --define='_smp_mflags %{nil}' --define='make $(MAKE)' # srcrpm-pkg # --------------------------------------------------------------------------- @@ -89,7 +89,8 @@ binrpm-pkg: $(MAKE) -f $(srctree)/Makefile $(CONFIG_SHELL) $(MKSPEC) prebuilt > $(objtree)/binkernel.spec +rpmbuild $(RPMOPTS) --define "_builddir $(objtree)" --target \ - $(UTS_MACHINE)-linux -bb $(objtree)/binkernel.spec + $(UTS_MACHINE)-linux -bb $(objtree)/binkernel.spec \ + --define='make $(MAKE)' # deb-pkg srcdeb-pkg bindeb-pkg # --------------------------------------------------------------------------- diff --git a/scripts/package/mkspec b/scripts/package/mkspec index a83b17b4a0d96..9b2b4386019d2 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -38,6 +38,8 @@ EXCLUDES="$RCS_TAR_IGNORE --exclude=*vmlinux* --exclude=*.mod \ # $S: this line is enabled only when building source package # $M: this line is enabled only when CONFIG_MODULES is enabled sed -e '/^DEL/d' -e 's/^\t*//' < Date: Sat, 22 Jul 2023 13:47:51 +0900 Subject: [PATCH 0377/3445] kbuild: rpm-pkg: use %{makeflags} to pass common Make options This is useful to pass more common Make options. Signed-off-by: Masahiro Yamada --- scripts/package/mkspec | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/scripts/package/mkspec b/scripts/package/mkspec index 9b2b4386019d2..a1ce6677880ab 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -39,6 +39,7 @@ EXCLUDES="$RCS_TAR_IGNORE --exclude=*vmlinux* --exclude=*.mod \ # $M: this line is enabled only when CONFIG_MODULES is enabled sed -e '/^DEL/d' -e 's/^\t*//' < Date: Sat, 22 Jul 2023 13:47:52 +0900 Subject: [PATCH 0378/3445] kbuild: rpm-pkg: record ARCH option in spec file Currently, we rely on the top Makefile defining ARCH option when we run 'make rpm-pkg' or 'make binrpm-pkg'. It does not apply when we run 'make srcrpm-pkg', and separately run 'rpmbuild' for the generated SRPM. This is a problem for cross-build. Just like the Debian package, save the value of ARCH in the spec file. Signed-off-by: Masahiro Yamada --- scripts/package/mkspec | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/package/mkspec b/scripts/package/mkspec index a1ce6677880ab..0befb4e2ac6b7 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -38,8 +38,10 @@ EXCLUDES="$RCS_TAR_IGNORE --exclude=*vmlinux* --exclude=*.mod \ # $S: this line is enabled only when building source package # $M: this line is enabled only when CONFIG_MODULES is enabled sed -e '/^DEL/d' -e 's/^\t*//' < Date: Sat, 22 Jul 2023 13:47:53 +0900 Subject: [PATCH 0379/3445] kbuild: rpm-pkg: replace $__KERNELRELEASE in spec file with %{version} ${version} will be replaced with the value of the Version field. Signed-off-by: Masahiro Yamada --- scripts/package/mkspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/package/mkspec b/scripts/package/mkspec index 0befb4e2ac6b7..a6a383aaaea7d 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -81,12 +81,12 @@ $S BuildRequires: gcc make openssl openssl-devel perl python3 rsync glibc package. $S$M %package devel -$S$M Summary: Development package for building kernel modules to match the $__KERNELRELEASE kernel +$S$M Summary: Development package for building kernel modules to match the %{version} kernel $S$M Group: System Environment/Kernel $S$M AutoReqProv: no $S$M %description -n kernel-devel $S$M This package provides kernel headers and makefiles sufficient to build modules -$S$M against the $__KERNELRELEASE kernel package. +$S$M against the %{version} kernel package. $S$M $S %prep $S %setup -q -n linux -- GitLab From 93ed5605c6185edf3b47c433b257c00854f0a4e1 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 22 Jul 2023 13:47:54 +0900 Subject: [PATCH 0380/3445] kbuild: rpm-pkg: replace $KERNELRELEASE in spec file with %{KERNELRELEASE} Avoid hard-coding the value of KERNELRELEASE in the generated spec file. Signed-off-by: Masahiro Yamada --- scripts/package/mkspec | 59 +++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/scripts/package/mkspec b/scripts/package/mkspec index a6a383aaaea7d..34b2489106cf2 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -39,6 +39,7 @@ EXCLUDES="$RCS_TAR_IGNORE --exclude=*vmlinux* --exclude=*.mod \ # $M: this line is enabled only when CONFIG_MODULES is enabled sed -e '/^DEL/d' -e 's/^\t*//' < Date: Sat, 22 Jul 2023 13:47:55 +0900 Subject: [PATCH 0381/3445] kbuild: add a phony target to run a command with Kbuild env vars There are some cases where we want to run a command with the same environment variables as Kbuild uses. For example, 'make coccicheck' invokes scripts/coccicheck from the top Makefile so that the script can reference to ${LINUXINCLUDE}, ${KBUILD_EXTMOD}, etc. The top Makefile defines several phony targets that run a script. We do it also for an internally used script, which results in a somewhat complex call graph. One example: debian/rules binary-arch -> make intdeb-pkg -> scripts/package/builddeb It is also tedious to add a dedicated target like 'intdeb-pkg' for each use case. Add a generic target 'run-command' to run an arbitrary command in an environment with all Kbuild variables set. The usage is: $ make run-command KBUILD_RUN_COMMAND= The concept is similar to: $ dpkg-architecture -c This executes in an environment which has all DEB_* variables defined. Convert the existing 'make intdeb-pkg'. Another possible usage is to interrogate a Make variable. $ make run-command KBUILD_RUN_COMMAND='echo $(KBUILD_CFLAGS)' might be useful to see KBUILD_CFLAGS set by the top Makefile. Signed-off-by: Masahiro Yamada --- Makefile | 4 ++++ scripts/Makefile.package | 4 ---- scripts/package/mkdebian | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index d36e5361810fa..8533ba64713c1 100644 --- a/Makefile +++ b/Makefile @@ -2148,6 +2148,10 @@ kernelversion: image_name: @echo $(KBUILD_IMAGE) +PHONY += run-command +run-command: + $(Q)$(KBUILD_RUN_COMMAND) + quiet_cmd_rmfiles = $(if $(wildcard $(rm-files)),CLEAN $(wildcard $(rm-files))) cmd_rmfiles = rm -rf $(rm-files) diff --git a/scripts/Makefile.package b/scripts/Makefile.package index e9217e997c683..7cd61a374dae7 100644 --- a/scripts/Makefile.package +++ b/scripts/Makefile.package @@ -146,10 +146,6 @@ deb-pkg srcdeb-pkg bindeb-pkg: --no-check-builddeps) \ $(DPKG_FLAGS)) -PHONY += intdeb-pkg -intdeb-pkg: - +$(CONFIG_SHELL) $(srctree)/scripts/package/builddeb - # snap-pkg # --------------------------------------------------------------------------- PHONY += snap-pkg diff --git a/scripts/package/mkdebian b/scripts/package/mkdebian index ba2453e08d408..9105abab9728c 100755 --- a/scripts/package/mkdebian +++ b/scripts/package/mkdebian @@ -283,7 +283,8 @@ build: build-arch binary-indep: binary-arch: build-arch \$(MAKE) -f \$(srctree)/Makefile ARCH=${ARCH} \ - KERNELRELEASE=\$(KERNELRELEASE) intdeb-pkg + KERNELRELEASE=\$(KERNELRELEASE) \ + run-command KBUILD_RUN_COMMAND=+\$(srctree)/scripts/package/builddeb clean: rm -rf debian/files debian/linux-* -- GitLab From fe66b5d2ae72121c9f4f705dbae36d4c3e9f3812 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 22 Jul 2023 13:47:56 +0900 Subject: [PATCH 0382/3445] kbuild: refactor kernel-devel RPM package and linux-headers Deb package The kernel-devel RPM package and the linux-headers Debian package provide headers and scripts needed for building external modules. They copy the necessary files in slightly different ways - the RPM copies almost everything except some exclude patterns, while the Debian copies less number of files. There is no need to maintain different code to do the same thing. Split the Debian code out to scripts/package/install-extmod-build, which is called from both of the packages. Signed-off-by: Masahiro Yamada --- scripts/package/builddeb | 29 +-------------------- scripts/package/install-extmod-build | 39 ++++++++++++++++++++++++++++ scripts/package/mkspec | 6 +---- 3 files changed, 41 insertions(+), 33 deletions(-) create mode 100755 scripts/package/install-extmod-build diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 032774eb061e1..bf3f8561aa683 100755 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -162,34 +162,7 @@ install_kernel_headers () { rm -rf $pdir - ( - cd $srctree - find . arch/$SRCARCH -maxdepth 1 -name Makefile\* - find include scripts -type f -o -type l - find arch/$SRCARCH -name Kbuild.platforms -o -name Platform - find $(find arch/$SRCARCH -name include -o -name scripts -type d) -type f - ) > debian/hdrsrcfiles - - { - if is_enabled CONFIG_OBJTOOL; then - echo tools/objtool/objtool - fi - - find arch/$SRCARCH/include Module.symvers include scripts -type f - - if is_enabled CONFIG_GCC_PLUGINS; then - find scripts/gcc-plugins -name \*.so - fi - } > debian/hdrobjfiles - - destdir=$pdir/usr/src/linux-headers-$version - mkdir -p $destdir - tar -c -f - -C $srctree -T debian/hdrsrcfiles | tar -xf - -C $destdir - tar -c -f - -T debian/hdrobjfiles | tar -xf - -C $destdir - rm -f debian/hdrsrcfiles debian/hdrobjfiles - - # copy .config manually to be where it's expected to be - cp $KCONFIG_CONFIG $destdir/.config + "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" mkdir -p $pdir/lib/modules/$version/ ln -s /usr/src/linux-headers-$version $pdir/lib/modules/$version/build diff --git a/scripts/package/install-extmod-build b/scripts/package/install-extmod-build new file mode 100755 index 0000000000000..af7fe9f5b1e4d --- /dev/null +++ b/scripts/package/install-extmod-build @@ -0,0 +1,39 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only + +set -e + +destdir=${1} + +test -n "${srctree}" +test -n "${SRCARCH}" + +is_enabled() { + grep -q "^$1=y" include/config/auto.conf +} + +mkdir -p "${destdir}" + +( + cd "${srctree}" + echo Makefile + find "arch/${SRCARCH}" -maxdepth 1 -name 'Makefile*' + find include scripts -type f -o -type l + find "arch/${SRCARCH}" -name Kbuild.platforms -o -name Platform + find "$(find "arch/${SRCARCH}" -name include -o -name scripts -type d)" -type f +) | tar -c -f - -C "${srctree}" -T - | tar -xf - -C "${destdir}" + +{ + if is_enabled CONFIG_OBJTOOL; then + echo tools/objtool/objtool + fi + + find "arch/${SRCARCH}/include" Module.symvers include scripts -type f + + if is_enabled CONFIG_GCC_PLUGINS; then + find scripts/gcc-plugins -name '*.so' + fi +} | tar -c -f - -T - | tar -xf - -C "${destdir}" + +# copy .config manually to be where it's expected to be +cp "${KCONFIG_CONFIG}" "${destdir}/.config" diff --git a/scripts/package/mkspec b/scripts/package/mkspec index 34b2489106cf2..22e290d23d8ae 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -28,9 +28,6 @@ else fi __KERNELRELEASE=$(echo $KERNELRELEASE | sed -e "s/-/_/g") -EXCLUDES="$RCS_TAR_IGNORE --exclude=*vmlinux* --exclude=*.mod \ ---exclude=*.o --exclude=*.ko --exclude=*.cmd --exclude=Documentation \ ---exclude=.config.old --exclude=.missing-syscalls.d --exclude=*.s" # We can label the here-doc lines for conditional output to the spec file # @@ -112,8 +109,7 @@ $M %{make} %{makeflags} INSTALL_MOD_PATH=%{buildroot} modules_install cp .config %{buildroot}/boot/config-%{KERNELRELEASE} $S$M rm -f %{buildroot}/lib/modules/%{KERNELRELEASE}/build $S$M rm -f %{buildroot}/lib/modules/%{KERNELRELEASE}/source -$S$M mkdir -p %{buildroot}/usr/src/kernels/%{KERNELRELEASE} -$S$M tar cf - $EXCLUDES . | tar xf - -C %{buildroot}/usr/src/kernels/%{KERNELRELEASE} +$S$M %{make} %{makeflags} run-command KBUILD_RUN_COMMAND='\${srctree}/scripts/package/install-extmod-build %{buildroot}/usr/src/kernels/%{KERNELRELEASE}' $S$M cd %{buildroot}/lib/modules/%{KERNELRELEASE} $S$M ln -sf /usr/src/kernels/%{KERNELRELEASE} build $S$M ln -sf /usr/src/kernels/%{KERNELRELEASE} source -- GitLab From d5d2d4cc60888f02dd4a6b2bfb03ff2fd7be4fc2 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 22 Jul 2023 13:47:57 +0900 Subject: [PATCH 0383/3445] kbuild: rpm-pkg: derive the Version from %{KERNELRELEASE} Avoid hard-coding the Version field in the generated spec file. Signed-off-by: Masahiro Yamada --- scripts/package/mkspec | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/package/mkspec b/scripts/package/mkspec index 22e290d23d8ae..783e1997d94ae 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -27,8 +27,6 @@ else M=DEL fi -__KERNELRELEASE=$(echo $KERNELRELEASE | sed -e "s/-/_/g") - # We can label the here-doc lines for conditional output to the spec file # # Labels: @@ -43,7 +41,7 @@ sed -e '/^DEL/d' -e 's/^\t*//' </dev/null || echo 1) License: GPL Group: System Environment/Kernel -- GitLab From d4f651277e9208b580b55da212e17ddd309c91e7 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 22 Jul 2023 13:47:58 +0900 Subject: [PATCH 0384/3445] kbuild: rpm-pkg: use a dummy string for _arch when undefined If this affects only %{buildroot}, it should be enough to use a fixed string for _arch when it is undefined. Signed-off-by: Masahiro Yamada --- scripts/package/mkspec | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/package/mkspec b/scripts/package/mkspec index 783e1997d94ae..22b980cf3d00d 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -36,6 +36,8 @@ sed -e '/^DEL/d' -e 's/^\t*//' < Date: Sat, 22 Jul 2023 13:47:59 +0900 Subject: [PATCH 0385/3445] kbuild: rpm-pkg: invoke the kernel build from rpmbuild for binrpm-pkg To reduce the preprocess of the spec file, invoke the kernel build from rpmbuild. Run init/build-version to increment the release number not only for binrpm-pkg but also for srcrpm-pkg and rpm-pkg. Signed-off-by: Masahiro Yamada --- scripts/Makefile.package | 2 +- scripts/package/mkspec | 31 ++++++++++++++++--------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/scripts/Makefile.package b/scripts/Makefile.package index 7cd61a374dae7..8373644a0473f 100644 --- a/scripts/Makefile.package +++ b/scripts/Makefile.package @@ -86,10 +86,10 @@ srcrpm-pkg: linux.tar.gz # --------------------------------------------------------------------------- PHONY += binrpm-pkg binrpm-pkg: - $(MAKE) -f $(srctree)/Makefile $(CONFIG_SHELL) $(MKSPEC) prebuilt > $(objtree)/binkernel.spec +rpmbuild $(RPMOPTS) --define "_builddir $(objtree)" --target \ $(UTS_MACHINE)-linux -bb $(objtree)/binkernel.spec \ + --build-in-place --noprep --define='_smp_mflags %{nil}' \ --define='make $(MAKE)' # deb-pkg srcdeb-pkg bindeb-pkg diff --git a/scripts/package/mkspec b/scripts/package/mkspec index 22b980cf3d00d..a9425d9936677 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -35,6 +35,7 @@ fi sed -e '/^DEL/d' -e 's/^\t*//' </dev/null || echo 1) + Release: %{pkg_release} License: GPL Group: System Environment/Kernel Vendor: The Linux Community URL: https://www.kernel.org -$S Source0: linux.tar.gz -$S Source1: config -$S Source2: diff.patch + Source0: linux.tar.gz + Source1: config + Source2: diff.patch Provides: kernel-%{KERNELRELEASE} -$S BuildRequires: bc binutils bison dwarves -$S BuildRequires: (elfutils-libelf-devel or libelf-devel) flex -$S BuildRequires: gcc make openssl openssl-devel perl python3 rsync + BuildRequires: bc binutils bison dwarves + BuildRequires: (elfutils-libelf-devel or libelf-devel) flex + BuildRequires: gcc make openssl openssl-devel perl python3 rsync %define __spec_install_post /usr/lib/rpm/brp-compress || : %define debug_package %{nil} @@ -83,14 +84,14 @@ $S$M %description -n kernel-devel $S$M This package provides kernel headers and makefiles sufficient to build modules $S$M against the %{version} kernel package. $S$M -$S %prep -$S %setup -q -n linux -$S cp %{SOURCE1} .config -$S patch -p1 < %{SOURCE2} -$S -$S %build -$S %{make} %{makeflags} KERNELRELEASE=%{KERNELRELEASE} KBUILD_BUILD_VERSION=%{release} -$S + %prep + %setup -q -n linux + cp %{SOURCE1} .config + patch -p1 < %{SOURCE2} + + %build + %{make} %{makeflags} KERNELRELEASE=%{KERNELRELEASE} KBUILD_BUILD_VERSION=%{release} + %install mkdir -p %{buildroot}/boot %ifarch ia64 -- GitLab From b537925fdd689ca33b6d9eed4569bc625550b3ef Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 22 Jul 2023 13:48:00 +0900 Subject: [PATCH 0386/3445] kbuild: rpm-pkg: run modules_install for non-modular kernel For the same reason as commit 4243afdb9326 ("kbuild: builddeb: always make modules_install, to install modules.builtin*"), run modules_install even when CONFIG_MODULES=n to install modules.builtin*. Signed-off-by: Masahiro Yamada --- scripts/package/mkspec | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/scripts/package/mkspec b/scripts/package/mkspec index a9425d9936677..2613e85cd8449 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -101,16 +101,13 @@ $S$M %else cp \$(%{make} %{makeflags} -s image_name) %{buildroot}/boot/vmlinuz-%{KERNELRELEASE} %endif -$M %{make} %{makeflags} INSTALL_MOD_PATH=%{buildroot} modules_install + %{make} %{makeflags} INSTALL_MOD_PATH=%{buildroot} modules_install %{make} %{makeflags} INSTALL_HDR_PATH=%{buildroot}/usr headers_install cp System.map %{buildroot}/boot/System.map-%{KERNELRELEASE} cp .config %{buildroot}/boot/config-%{KERNELRELEASE} -$S$M rm -f %{buildroot}/lib/modules/%{KERNELRELEASE}/build -$S$M rm -f %{buildroot}/lib/modules/%{KERNELRELEASE}/source + ln -fns /usr/src/kernels/%{KERNELRELEASE} %{buildroot}/lib/modules/%{KERNELRELEASE}/build + ln -fns /usr/src/kernels/%{KERNELRELEASE} %{buildroot}/lib/modules/%{KERNELRELEASE}/source $S$M %{make} %{makeflags} run-command KBUILD_RUN_COMMAND='\${srctree}/scripts/package/install-extmod-build %{buildroot}/usr/src/kernels/%{KERNELRELEASE}' -$S$M cd %{buildroot}/lib/modules/%{KERNELRELEASE} -$S$M ln -sf /usr/src/kernels/%{KERNELRELEASE} build -$S$M ln -sf /usr/src/kernels/%{KERNELRELEASE} source %clean rm -rf %{buildroot} @@ -138,9 +135,9 @@ $S$M ln -sf /usr/src/kernels/%{KERNELRELEASE} source %files %defattr (-, root, root) -$M /lib/modules/%{KERNELRELEASE} -$M %exclude /lib/modules/%{KERNELRELEASE}/build -$M %exclude /lib/modules/%{KERNELRELEASE}/source + /lib/modules/%{KERNELRELEASE} + %exclude /lib/modules/%{KERNELRELEASE}/build + %exclude /lib/modules/%{KERNELRELEASE}/source /boot/* %files headers -- GitLab From 2a291fc315b6aec2f209aa44da90515ddd4f89d0 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 22 Jul 2023 13:48:01 +0900 Subject: [PATCH 0387/3445] kbuild: rpm-pkg: introduce %{with_devel} switch to select devel package scripts/package/mkspec preprocesses the spec file by sed, but it is unreadable. This commit removes the last portion of the sed scripting. Remove the $S$M prefixes from the conditionally generated lines. Instead, surround the code with %if %{with_devel} ... %endif. Signed-off-by: Masahiro Yamada --- scripts/Makefile.package | 2 +- scripts/package/mkspec | 53 +++++++++++++++++++--------------------- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/scripts/Makefile.package b/scripts/Makefile.package index 8373644a0473f..c36ae03d6002e 100644 --- a/scripts/Makefile.package +++ b/scripts/Makefile.package @@ -89,7 +89,7 @@ binrpm-pkg: $(CONFIG_SHELL) $(MKSPEC) prebuilt > $(objtree)/binkernel.spec +rpmbuild $(RPMOPTS) --define "_builddir $(objtree)" --target \ $(UTS_MACHINE)-linux -bb $(objtree)/binkernel.spec \ - --build-in-place --noprep --define='_smp_mflags %{nil}' \ + --build-in-place --noprep --define='_smp_mflags %{nil}' --without devel \ --define='make $(MAKE)' # deb-pkg srcdeb-pkg bindeb-pkg diff --git a/scripts/package/mkspec b/scripts/package/mkspec index 2613e85cd8449..511cae46a90d7 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -10,11 +10,7 @@ # # how we were called determines which rpms we build and how we build them -if [ "$1" = prebuilt ]; then - S=DEL -else - S= - +if [ -z "$1" ]; then mkdir -p rpmbuild/SOURCES cp linux.tar.gz rpmbuild/SOURCES cp "${KCONFIG_CONFIG}" rpmbuild/SOURCES/config @@ -22,17 +18,12 @@ else fi if grep -q CONFIG_MODULES=y include/config/auto.conf; then - M= +echo '%define with_devel %{?_without_devel: 0} %{?!_without_devel: 1}' else - M=DEL +echo '%define with_devel 0' fi -# We can label the here-doc lines for conditional output to the spec file -# -# Labels: -# $S: this line is enabled only when building source package -# $M: this line is enabled only when CONFIG_MODULES is enabled -sed -e '/^DEL/d' -e 's/^\t*//' < Date: Sat, 22 Jul 2023 13:48:03 +0900 Subject: [PATCH 0389/3445] kbuild: rpm-pkg: rename binkernel.spec to kernel.spec Now kernel.spec and binkernel.spec have the exactly same contents. Use kernel.spec for binrpm-pkg as well. Signed-off-by: Masahiro Yamada --- .gitignore | 2 +- Makefile | 2 +- scripts/Makefile.package | 4 ++-- scripts/remove-stale-files | 2 ++ 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 9fd4c9533b3dc..0bbae167bf93e 100644 --- a/.gitignore +++ b/.gitignore @@ -74,7 +74,7 @@ modules.order # # RPM spec file (make rpm-pkg) # -/*.spec +/kernel.spec /rpmbuild/ # diff --git a/Makefile b/Makefile index 8533ba64713c1..4425d87dd2fac 100644 --- a/Makefile +++ b/Makefile @@ -1610,7 +1610,7 @@ MRPROPER_FILES += include/config include/generated \ certs/signing_key.pem \ certs/x509.genkey \ vmlinux-gdb.py \ - *.spec rpmbuild \ + kernel.spec rpmbuild \ rust/libmacros.so # clean - Delete most, but leave enough to build external modules diff --git a/scripts/Makefile.package b/scripts/Makefile.package index c36ae03d6002e..be9602fa98da6 100644 --- a/scripts/Makefile.package +++ b/scripts/Makefile.package @@ -86,9 +86,9 @@ srcrpm-pkg: linux.tar.gz # --------------------------------------------------------------------------- PHONY += binrpm-pkg binrpm-pkg: - $(CONFIG_SHELL) $(MKSPEC) prebuilt > $(objtree)/binkernel.spec + $(CONFIG_SHELL) $(MKSPEC) prebuilt > $(objtree)/kernel.spec +rpmbuild $(RPMOPTS) --define "_builddir $(objtree)" --target \ - $(UTS_MACHINE)-linux -bb $(objtree)/binkernel.spec \ + $(UTS_MACHINE)-linux -bb $(objtree)/kernel.spec \ --build-in-place --noprep --define='_smp_mflags %{nil}' --without devel \ --define='make $(MAKE)' diff --git a/scripts/remove-stale-files b/scripts/remove-stale-files index f3659ea0335bb..8b1a636f85434 100755 --- a/scripts/remove-stale-files +++ b/scripts/remove-stale-files @@ -37,3 +37,5 @@ rm -f .scmversion rm -rf include/ksym find . -name '*.usyms' | xargs rm -f + +rm -f binkernel.spec -- GitLab From 6db9ced4641fab2710e83c4d703e9ad60dd3ccf5 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 22 Jul 2023 13:48:04 +0900 Subject: [PATCH 0390/3445] kbuild: rpm-pkg: build the kernel in-place for rpm-pkg Currently, 'make rpm-pkg' always builds the kernel from the pristine source tree in the ~/rpmbuild/BUILD/ directory. Build the kernel incrementally just like 'make binrpm-pkg'. Signed-off-by: Masahiro Yamada --- scripts/Makefile.package | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/Makefile.package b/scripts/Makefile.package index be9602fa98da6..bf2da97f29d0e 100644 --- a/scripts/Makefile.package +++ b/scripts/Makefile.package @@ -72,6 +72,7 @@ PHONY += rpm-pkg rpm-pkg: srpm = $(shell rpmspec --srpm --query --queryformat='%{name}-%{VERSION}-%{RELEASE}.src.rpm' kernel.spec) rpm-pkg: srcrpm-pkg +rpmbuild $(RPMOPTS) --target $(UTS_MACHINE)-linux -rb $(srpm) \ + --build-in-place --noprep \ --define='_smp_mflags %{nil}' --define='make $(MAKE)' # srcrpm-pkg -- GitLab From 37477496d6aa91248184238a95b59b7d91d46921 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 22 Jul 2023 13:48:05 +0900 Subject: [PATCH 0391/3445] kbuild: rpm-pkg: refactor *rpm-pkg targets Merge the similar build targets. Also, make the output location consistent. Previously, source packages were created in the build directory, while binary packages under ~/rpmbuild/RPMS/. Now, Kbuild creates the rpmbuild/ directory in the build directory, and saves all packages under it. Signed-off-by: Masahiro Yamada --- scripts/Makefile.package | 54 +++++++++++++++++++++------------------- scripts/package/mkspec | 8 ------ 2 files changed, 29 insertions(+), 33 deletions(-) diff --git a/scripts/Makefile.package b/scripts/Makefile.package index bf2da97f29d0e..0ace3973a0d14 100644 --- a/scripts/Makefile.package +++ b/scripts/Makefile.package @@ -11,7 +11,6 @@ TAR_CONTENT := Documentation LICENSES arch block certs crypto drivers fs \ samples scripts security sound tools usr virt \ .config Makefile \ Kbuild Kconfig COPYING $(wildcard localversion*) -MKSPEC := $(srctree)/scripts/package/mkspec quiet_cmd_src_tar = TAR $(2).tar.gz cmd_src_tar = \ @@ -66,32 +65,37 @@ $(linux-tarballs): archive-args = --prefix=linux/ $$(cat $<) $(linux-tarballs): .tmp_HEAD FORCE $(call if_changed,archive) -# rpm-pkg +# rpm-pkg srcrpm-pkg binrpm-pkg # --------------------------------------------------------------------------- -PHONY += rpm-pkg -rpm-pkg: srpm = $(shell rpmspec --srpm --query --queryformat='%{name}-%{VERSION}-%{RELEASE}.src.rpm' kernel.spec) -rpm-pkg: srcrpm-pkg - +rpmbuild $(RPMOPTS) --target $(UTS_MACHINE)-linux -rb $(srpm) \ - --build-in-place --noprep \ - --define='_smp_mflags %{nil}' --define='make $(MAKE)' - -# srcrpm-pkg -# --------------------------------------------------------------------------- -PHONY += srcrpm-pkg -srcrpm-pkg: linux.tar.gz - $(CONFIG_SHELL) $(MKSPEC) >$(objtree)/kernel.spec - +rpmbuild $(RPMOPTS) --target $(UTS_MACHINE)-linux -bs kernel.spec \ - --define='_smp_mflags %{nil}' --define='_sourcedir rpmbuild/SOURCES' --define='_srcrpmdir .' -# binrpm-pkg -# --------------------------------------------------------------------------- -PHONY += binrpm-pkg -binrpm-pkg: - $(CONFIG_SHELL) $(MKSPEC) prebuilt > $(objtree)/kernel.spec - +rpmbuild $(RPMOPTS) --define "_builddir $(objtree)" --target \ - $(UTS_MACHINE)-linux -bb $(objtree)/kernel.spec \ - --build-in-place --noprep --define='_smp_mflags %{nil}' --without devel \ - --define='make $(MAKE)' +quiet_cmd_mkspec = GEN $@ + cmd_mkspec = $(srctree)/scripts/package/mkspec > $@ + +kernel.spec: FORCE + $(call cmd,mkspec) + +PHONY += rpm-sources +rpm-sources: linux.tar.gz + $(Q)mkdir -p rpmbuild/SOURCES + $(Q)ln -f linux.tar.gz rpmbuild/SOURCES/linux.tar.gz + $(Q)cp $(KCONFIG_CONFIG) rpmbuild/SOURCES/config + $(Q)$(srctree)/scripts/package/gen-diff-patch rpmbuild/SOURCES/diff.patch + +PHONY += rpm-pkg srcrpm-pkg binrpm-pkg + +rpm-pkg: private build-type := a +srcrpm-pkg: private build-type := s +binrpm-pkg: private build-type := b + +rpm-pkg srcrpm-pkg: rpm-sources +rpm-pkg srcrpm-pkg binrpm-pkg: kernel.spec + +$(strip rpmbuild -b$(build-type) kernel.spec \ + --define='_topdir $(abspath rpmbuild)' \ + $(if $(filter a b, $(build-type)), \ + --target $(UTS_MACHINE)-linux --build-in-place --noprep --define='_smp_mflags %{nil}') \ + $(if $(filter b, $(build-type)), \ + --without devel) \ + $(RPMOPTS)) # deb-pkg srcdeb-pkg bindeb-pkg # --------------------------------------------------------------------------- diff --git a/scripts/package/mkspec b/scripts/package/mkspec index c08567ae7fb18..d41608efb7474 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -9,14 +9,6 @@ # Patched for non-x86 by Opencon (L) 2002 # -# how we were called determines which rpms we build and how we build them -if [ -z "$1" ]; then - mkdir -p rpmbuild/SOURCES - cp linux.tar.gz rpmbuild/SOURCES - cp "${KCONFIG_CONFIG}" rpmbuild/SOURCES/config - "${srctree}/scripts/package/gen-diff-patch" rpmbuild/SOURCES/diff.patch -fi - if grep -q CONFIG_MODULES=y include/config/auto.conf; then echo '%define with_devel %{?_without_devel: 0} %{?!_without_devel: 1}' else -- GitLab From 783c55ae7a9551f049b0c1a52cde0ec3a5550501 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 22 Jul 2023 13:48:06 +0900 Subject: [PATCH 0392/3445] kbuild: rpm-pkg: skip build dependency check on non-rpm systems Commit 8818039f959b ("kbuild: add ability to make source rpm buildable using koji") added the BuildRequires: field. Checking the build dependency is fine, but one annoyance is that 'make (bin)rpm-pkg' fails on non-rpm systems [1]. For example, Debian provides rpmbuild via 'apt install rpm', but of course cannot meet the requirement listed in the BuildRequires: field. It is possible to pass RPMOPTS=--nodeps to work around it, but it is reasonable to do it automatically. If 'rpm -q rpm' fails, it is not an RPM-managed system. (The command 'rpm' is not installed at all, or was installed by other means.) In that case, pass --nodeps to skip the build dependency check. [1]: https://lore.kernel.org/linux-kbuild/Y6mkdYQYmjUz7bqV@li-4a3a4a4c-28e5-11b2-a85c-a8d192c6f089.ibm.com/ Signed-off-by: Masahiro Yamada --- scripts/Makefile.package | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/Makefile.package b/scripts/Makefile.package index 0ace3973a0d14..85beab0363d78 100644 --- a/scripts/Makefile.package +++ b/scripts/Makefile.package @@ -92,7 +92,8 @@ rpm-pkg srcrpm-pkg binrpm-pkg: kernel.spec +$(strip rpmbuild -b$(build-type) kernel.spec \ --define='_topdir $(abspath rpmbuild)' \ $(if $(filter a b, $(build-type)), \ - --target $(UTS_MACHINE)-linux --build-in-place --noprep --define='_smp_mflags %{nil}') \ + --target $(UTS_MACHINE)-linux --build-in-place --noprep --define='_smp_mflags %{nil}' \ + $$(rpm -q rpm >/dev/null 2>&1 || echo --nodeps)) \ $(if $(filter b, $(build-type)), \ --without devel) \ $(RPMOPTS)) -- GitLab From 91f88a0ac8bce5f385ef8c1a6766fce04f7f0043 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 24 Jul 2023 13:12:44 -0700 Subject: [PATCH 0393/3445] perf stat: Avoid uninitialized use of perf_stat_config perf_event__read_stat_config will assign values based on number of tags and tag values. Initialize the structs to zero before they are assigned so that no uninitialized values can be seen. This potential error was reported by GCC with LTO enabled. Reviewed-by: Nick Desaulniers Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Carsten Haitzler Cc: Fangrui Song Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Tom Rix Cc: Xing Zhengjun Cc: Yang Jihong Cc: bpf@vger.kernel.org Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230724201247.748146-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/stat.c | 2 +- tools/perf/util/stat.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/tests/stat.c b/tools/perf/tests/stat.c index 500974040fe31..706780fb56951 100644 --- a/tools/perf/tests/stat.c +++ b/tools/perf/tests/stat.c @@ -27,7 +27,7 @@ static int process_stat_config_event(struct perf_tool *tool __maybe_unused, struct machine *machine __maybe_unused) { struct perf_record_stat_config *config = &event->stat_config; - struct perf_stat_config stat_config; + struct perf_stat_config stat_config = {}; #define HAS(term, val) \ has_term(config, PERF_STAT_CONFIG_TERM__##term, val) diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 967e583392c71..ec35060422173 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -729,7 +729,7 @@ size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp) size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp) { - struct perf_stat_config sc; + struct perf_stat_config sc = {}; size_t ret; perf_event__read_stat_config(&sc, &event->stat_config); -- GitLab From 0f97a3a0deccece93797cd35ba1c18704e94b7e7 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 24 Jul 2023 13:12:45 -0700 Subject: [PATCH 0394/3445] perf parse-events: Avoid use uninitialized warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With GCC LTO a potential use uninitialized is spotted: ``` In function ‘parse_events_config_bpf’, inlined from ‘parse_events_load_bpf’ at util/parse-events.c:874:8: util/parse-events.c:792:37: error: ‘error_pos’ may be used uninitialized [-Werror=maybe-uninitialized] 792 | idx = term->err_term + error_pos; | ^ util/parse-events.c: In function ‘parse_events_load_bpf’: util/parse-events.c:765:13: note: ‘error_pos’ was declared here 765 | int error_pos; | ^ ``` So initialize at declaration. Reviewed-by: Nick Desaulniers Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Carsten Haitzler Cc: Fangrui Song Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Tom Rix Cc: Xing Zhengjun Cc: Yang Jihong Cc: bpf@vger.kernel.org Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230724201247.748146-3-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index acde097e327cc..da29061ecf493 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -762,7 +762,7 @@ parse_events_config_bpf(struct parse_events_state *parse_state, struct list_head *head_config) { struct parse_events_term *term; - int error_pos; + int error_pos = 0; if (!head_config || list_empty(head_config)) return 0; -- GitLab From 5cfb0cc0d95af8bf33a8fb1cedc3e76ca3b6fb81 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 24 Jul 2023 13:12:46 -0700 Subject: [PATCH 0395/3445] perf test: Avoid weak symbol for arch_tests GCC LTO will complain that the array length varies for the arch_tests weak symbol. Use extern/static and architecture determining #if to workaround this problem. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Carsten Haitzler Cc: Fangrui Song Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Nick Desaulniers Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Tom Rix Cc: Xing Zhengjun Cc: Yang Jihong Cc: bpf@vger.kernel.org Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230724201247.748146-4-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/builtin-test.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 1f6557ce3b0ae..6accb5442a731 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -33,9 +33,18 @@ static bool dont_fork; const char *dso_to_test; -struct test_suite *__weak arch_tests[] = { +/* + * List of architecture specific tests. Not a weak symbol as the array length is + * dependent on the initialization, as such GCC with LTO complains of + * conflicting definitions with a weak symbol. + */ +#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__) +extern struct test_suite *arch_tests[]; +#else +static struct test_suite *arch_tests[] = { NULL, }; +#endif static struct test_suite *generic_tests[] = { &suite__vmlinux_matches_kallsyms, -- GitLab From c126ac4a2003fff398311739514f173944a5ceab Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 24 Jul 2023 13:12:47 -0700 Subject: [PATCH 0396/3445] perf build: Add LTO build option Add an LTO build option, that sets the appropriate CFLAGS and CXXFLAGS values. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Carsten Haitzler Cc: Fangrui Song Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Nick Desaulniers Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Tom Rix Cc: Xing Zhengjun Cc: Yang Jihong Cc: bpf@vger.kernel.org Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230724201247.748146-5-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.config | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index c5db0de498687..a9cfe83638a93 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -256,6 +256,11 @@ ifdef PARSER_DEBUG $(call detected_var,PARSER_DEBUG_FLEX) endif +ifdef LTO + CORE_CFLAGS += -flto + CXXFLAGS += -flto +endif + # Try different combinations to accommodate systems that only have # python[2][3]-config in weird combinations in the following order of # priority from lowest to highest: -- GitLab From 657c45b303f87d77eb4ef49e9452f1c5d1fc363c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Jul 2023 11:40:27 -0600 Subject: [PATCH 0397/3445] MIPS: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it was merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Signed-off-by: Thomas Bogendoerfer --- arch/mips/bmips/setup.c | 1 - arch/mips/cavium-octeon/flash_setup.c | 3 ++- arch/mips/lantiq/irq.c | 2 +- arch/mips/lantiq/xway/dcdc.c | 3 ++- arch/mips/lantiq/xway/gptu.c | 4 ++-- arch/mips/lantiq/xway/sysctrl.c | 1 - arch/mips/lantiq/xway/vmmc.c | 3 ++- arch/mips/pci/pci-lantiq.c | 4 ++-- arch/mips/pci/pci-rt2880.c | 5 ++--- arch/mips/pic32/pic32mzda/config.c | 1 - arch/mips/ralink/irq.c | 2 +- arch/mips/ralink/of.c | 2 +- arch/mips/ralink/prom.c | 2 -- 13 files changed, 15 insertions(+), 18 deletions(-) diff --git a/arch/mips/bmips/setup.c b/arch/mips/bmips/setup.c index 053805cb741c3..ec180ab92eaa8 100644 --- a/arch/mips/bmips/setup.c +++ b/arch/mips/bmips/setup.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/cavium-octeon/flash_setup.c b/arch/mips/cavium-octeon/flash_setup.c index c8a8c6d359b9c..3395acde4d60a 100644 --- a/arch/mips/cavium-octeon/flash_setup.c +++ b/arch/mips/cavium-octeon/flash_setup.c @@ -12,7 +12,8 @@ #include #include #include -#include +#include +#include #include #include diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c index 20622bf0a9b3d..8f208007b8e84 100644 --- a/arch/mips/lantiq/irq.c +++ b/arch/mips/lantiq/irq.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/mips/lantiq/xway/dcdc.c b/arch/mips/lantiq/xway/dcdc.c index 96199966a350d..4a808f8c5bebf 100644 --- a/arch/mips/lantiq/xway/dcdc.c +++ b/arch/mips/lantiq/xway/dcdc.c @@ -6,7 +6,8 @@ */ #include -#include +#include +#include #include diff --git a/arch/mips/lantiq/xway/gptu.c b/arch/mips/lantiq/xway/gptu.c index a492b1eb19250..e254b108fb9ba 100644 --- a/arch/mips/lantiq/xway/gptu.c +++ b/arch/mips/lantiq/xway/gptu.c @@ -8,8 +8,8 @@ #include #include #include -#include -#include +#include +#include #include #include "../clk.h" diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c index d444a1b98a724..3ed0782252229 100644 --- a/arch/mips/lantiq/xway/sysctrl.c +++ b/arch/mips/lantiq/xway/sysctrl.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include diff --git a/arch/mips/lantiq/xway/vmmc.c b/arch/mips/lantiq/xway/vmmc.c index 2796e87dfcae3..37c133052ef75 100644 --- a/arch/mips/lantiq/xway/vmmc.c +++ b/arch/mips/lantiq/xway/vmmc.c @@ -7,7 +7,8 @@ #include #include #include -#include +#include +#include #include #include diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c index 79e29bf42a241..80f7293166bb7 100644 --- a/arch/mips/pci/pci-lantiq.c +++ b/arch/mips/pci/pci-lantiq.c @@ -13,9 +13,9 @@ #include #include #include -#include -#include +#include #include +#include #include diff --git a/arch/mips/pci/pci-rt2880.c b/arch/mips/pci/pci-rt2880.c index e9dd01431f212..1cada09fa5db0 100644 --- a/arch/mips/pci/pci-rt2880.c +++ b/arch/mips/pci/pci-rt2880.c @@ -13,9 +13,8 @@ #include #include #include -#include -#include -#include +#include +#include #include diff --git a/arch/mips/pic32/pic32mzda/config.c b/arch/mips/pic32/pic32mzda/config.c index f695320077174..6e94ae66eba82 100644 --- a/arch/mips/pic32/pic32mzda/config.c +++ b/arch/mips/pic32/pic32mzda/config.c @@ -5,7 +5,6 @@ */ #include #include -#include #include diff --git a/arch/mips/ralink/irq.c b/arch/mips/ralink/irq.c index fa353bc139474..46aef0a1b22ac 100644 --- a/arch/mips/ralink/irq.c +++ b/arch/mips/ralink/irq.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c index 45d60c094496f..7f90068c68f22 100644 --- a/arch/mips/ralink/of.c +++ b/arch/mips/ralink/of.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/mips/ralink/prom.c b/arch/mips/ralink/prom.c index aaac1e6ec7d9a..c3b96861844c6 100644 --- a/arch/mips/ralink/prom.c +++ b/arch/mips/ralink/prom.c @@ -7,8 +7,6 @@ */ #include -#include -#include #include #include -- GitLab From a79a404e6c2241ebc528b9ebf4c0832457b498c3 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 18 Jul 2023 15:37:18 +0100 Subject: [PATCH 0398/3445] MIPS: Fix CONFIG_CPU_DADDI_WORKAROUNDS `modules_install' regression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove a build-time check for the presence of the GCC `-msym32' option. This option has been there since GCC 4.1.0, which is below the minimum required as at commit 805b2e1d427a ("kbuild: include Makefile.compiler only when compiler is needed"), when an error message: arch/mips/Makefile:306: *** CONFIG_CPU_DADDI_WORKAROUNDS unsupported without -msym32. Stop. started to trigger for the `modules_install' target with configurations such as `decstation_64_defconfig' that set CONFIG_CPU_DADDI_WORKAROUNDS, because said commit has made `cc-option-yn' an undefined function for non-build targets. Reported-by: Jan-Benedict Glaw Signed-off-by: Maciej W. Rozycki Fixes: 805b2e1d427a ("kbuild: include Makefile.compiler only when compiler is needed") Cc: stable@vger.kernel.org # v5.13+ Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Bogendoerfer --- arch/mips/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index a47593d72f6f5..69c18074d8177 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -299,8 +299,8 @@ ifdef CONFIG_64BIT endif endif - ifeq ($(KBUILD_SYM32)$(call cc-option-yn,-msym32), yy) - cflags-y += -msym32 -DKBUILD_64BIT_SYM32 + ifeq ($(KBUILD_SYM32), y) + cflags-$(KBUILD_SYM32) += -msym32 -DKBUILD_64BIT_SYM32 else ifeq ($(CONFIG_CPU_DADDI_WORKAROUNDS), y) $(error CONFIG_CPU_DADDI_WORKAROUNDS unsupported without -msym32) -- GitLab From 4fe4a6374c4db9ae2b849b61e84b58685dca565a Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 18 Jul 2023 15:37:23 +0100 Subject: [PATCH 0399/3445] MIPS: Only fiddle with CHECKFLAGS if `need-compiler' We have originally guarded fiddling with CHECKFLAGS in our arch Makefile by checking for the CONFIG_MIPS variable, not set for targets such as `distclean', etc. that neither include `.config' nor use the compiler. Starting from commit 805b2e1d427a ("kbuild: include Makefile.compiler only when compiler is needed") we have had a generic `need-compiler' variable explicitly telling us if the compiler will be used and thus its capabilities need to be checked and expressed in the form of compilation flags. If this variable is not set, then `make' functions such as `cc-option' are undefined, causing all kinds of weirdness to happen if we expect specific results to be returned, most recently: cc1: error: '-mloongson-mmi' must be used with '-mhard-float' messages with configurations such as `fuloong2e_defconfig' and the `modules_install' target, which does include `.config' and yet does not use the compiler. Replace the check for CONFIG_MIPS with one for `need-compiler' instead, so as to prevent the compiler from being ever called for CHECKFLAGS when not needed. Reported-by: Guillaume Tucker Closes: https://lore.kernel.org/r/85031c0c-d981-031e-8a50-bc4fad2ddcd8@collabora.com/ Signed-off-by: Maciej W. Rozycki Fixes: 805b2e1d427a ("kbuild: include Makefile.compiler only when compiler is needed") Cc: stable@vger.kernel.org # v5.13+ Reported-by: "kernelci.org bot" Signed-off-by: Thomas Bogendoerfer --- arch/mips/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 69c18074d8177..d624b87c150d6 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -341,7 +341,7 @@ KBUILD_CFLAGS += -fno-asynchronous-unwind-tables KBUILD_LDFLAGS += -m $(ld-emul) -ifdef CONFIG_MIPS +ifdef need-compiler CHECKFLAGS += $(shell $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -dM -E -x c /dev/null | \ grep -E -vw '__GNUC_(MINOR_|PATCHLEVEL_)?_' | \ sed -e "s/^\#define /-D'/" -e "s/ /'='/" -e "s/$$/'/" -e 's/\$$/&&/g') -- GitLab From 0859bdf1ace659e8981a82956920573c1f8203da Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 18 Jul 2023 15:37:27 +0100 Subject: [PATCH 0400/3445] Revert MIPS: Loongson: Fix build error when make modules_install Revert commit 531b3d1195d0 ("MIPS: Loongson: Fix build error when make modules_install"), which made `-march=loongson2e', `-march=loongson2f', and `-march=loongson3a' compilation options probed for even though GCC has supported them since 4.4.0, 4.4.0, and 4.6.0 respectively, which is below our current minimum requirement of 5.1, in an attempt to work around for the `cc-option' `make' function being undefined with `make' targets that do not use the compiler. The workaround has now been made obsolete, by querying the `need-compiler' variable instead so as to make sure the compiler isn't called for non-build targets. Verified with `fuloong2e_defconfig' and the `modules_install' target. Signed-off-by: Maciej W. Rozycki Signed-off-by: Thomas Bogendoerfer --- arch/mips/Makefile | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index d624b87c150d6..f49807e1f19bc 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -181,12 +181,16 @@ endif cflags-$(CONFIG_CAVIUM_CN63XXP1) += -Wa,-mfix-cn63xxp1 cflags-$(CONFIG_CPU_BMIPS) += -march=mips32 -Wa,-mips32 -Wa,--trap -cflags-$(CONFIG_CPU_LOONGSON2E) += $(call cc-option,-march=loongson2e) -Wa,--trap -cflags-$(CONFIG_CPU_LOONGSON2F) += $(call cc-option,-march=loongson2f) -Wa,--trap -cflags-$(CONFIG_CPU_LOONGSON64) += $(call cc-option,-march=loongson3a,-march=mips64r2) -Wa,--trap +cflags-$(CONFIG_CPU_LOONGSON2E) += -march=loongson2e -Wa,--trap +cflags-$(CONFIG_CPU_LOONGSON2F) += -march=loongson2f -Wa,--trap # Some -march= flags enable MMI instructions, and GCC complains about that # support being enabled alongside -msoft-float. Thus explicitly disable MMI. cflags-$(CONFIG_CPU_LOONGSON2EF) += $(call cc-option,-mno-loongson-mmi) +ifdef CONFIG_CPU_LOONGSON64 +cflags-$(CONFIG_CPU_LOONGSON64) += -Wa,--trap +cflags-$(CONFIG_CC_IS_GCC) += -march=loongson3a +cflags-$(CONFIG_CC_IS_CLANG) += -march=mips64r2 +endif cflags-$(CONFIG_CPU_LOONGSON64) += $(call cc-option,-mno-loongson-mmi) cflags-$(CONFIG_CPU_R4000_WORKAROUNDS) += $(call cc-option,-mfix-r4000,) -- GitLab From ec6beb82587c73cff52730567016cbc6c17822a8 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Tue, 25 Jul 2023 12:08:56 +0530 Subject: [PATCH 0401/3445] phy: starfive: make phys depend on HAS_IOMEM the startfive phy drivers use devm_platform_ioremap_resource() which on some archs (s390) is not present. So make the drivers depend on HAS_IOMEM Fixes: f8aa660841bc ("phy: starfive: Add mipi dphy rx support") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202307250509.oeudxG28-lkp@intel.com/ Reviewed-by: Changhuang Liang Signed-off-by: Vinod Koul Link: https://lore.kernel.org/r/20230725063856.482696-1-vkoul@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/starfive/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/phy/starfive/Kconfig b/drivers/phy/starfive/Kconfig index a560533a674ee..0508f9b123e0a 100644 --- a/drivers/phy/starfive/Kconfig +++ b/drivers/phy/starfive/Kconfig @@ -5,6 +5,7 @@ config PHY_STARFIVE_JH7110_DPHY_RX tristate "StarFive JH7110 D-PHY RX support" + depends on HAS_IOMEM select GENERIC_PHY select GENERIC_PHY_MIPI_DPHY help -- GitLab From 8362bf82fb5441613aac7c6c9dbb6b83def6ad3b Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 25 Jul 2023 08:37:56 -0700 Subject: [PATCH 0402/3445] Input: mcs-touchkey - fix uninitialized use of error in mcs_touchkey_probe() Clang warns (or errors with CONFIG_WERROR=y): drivers/input/keyboard/mcs_touchkey.c:149:49: error: variable 'error' is uninitialized when used here [-Werror,-Wuninitialized] 149 | dev_err(&client->dev, "i2c read error[%d]\n", error); | ^~~~~ include/linux/dev_printk.h:144:65: note: expanded from macro 'dev_err' 144 | dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__) | ^~~~~~~~~~~ include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap' 110 | _p_func(dev, fmt, ##__VA_ARGS__); \ | ^~~~~~~~~~~ drivers/input/keyboard/mcs_touchkey.c:110:11: note: initialize the variable 'error' to silence this warning 110 | int error; | ^ | = 0 1 error generated. A refactoring updated the error handling in this block but did not update the dev_err() call to use fw_ver instead of error. Do so now to fix the warning and avoid printing uninitialized memory. Closes: https://github.com/ClangBuiltLinux/linux/issues/1893 Fixes: e175eae16c1b ("Input: mcs-touchkey - convert to use devm_* api") Signed-off-by: Nathan Chancellor Link: https://lore.kernel.org/r/20230725-mcs_touchkey-fix-wuninitialized-v1-1-615db39af51c@kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/mcs_touchkey.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c index f25e2b20e2715..2410f676c7f95 100644 --- a/drivers/input/keyboard/mcs_touchkey.c +++ b/drivers/input/keyboard/mcs_touchkey.c @@ -146,7 +146,7 @@ static int mcs_touchkey_probe(struct i2c_client *client) fw_ver = i2c_smbus_read_byte_data(client, fw_reg); if (fw_ver < 0) { - dev_err(&client->dev, "i2c read error[%d]\n", error); + dev_err(&client->dev, "i2c read error[%d]\n", fw_ver); return fw_ver; } dev_info(&client->dev, "Firmware version: %d\n", fw_ver); -- GitLab From 65aca38b8ce728bf5a449b74f2a6a344167dfb02 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 24 Jul 2023 14:19:58 +0200 Subject: [PATCH 0403/3445] scsi: ufs: qcom: Remove unused variable A recent change removed the only user of a local variable that needs to now also be removed: drivers/ufs/host/ufs-qcom.c: In function 'ufs_qcom_mcq_esi_handler': drivers/ufs/host/ufs-qcom.c:1652:31: error: unused variable 'host' [-Werror=unused-variable] Fixes: 8f2b78652d05 ("scsi: ufs: qcom: Get queue ID from MSI index in ESI handler") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/llvm/64c00cd4.630a0220.6ad79.0eac@mx.google.com/ Link: https://lore.kernel.org/r/20230724122029.1430482-1-arnd@kernel.org Reviewed-by: Abel Vesa Reviewed-by: Manivannan Sadhasivam Reviewed-by: Nick Desaulniers Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 3ee5ff905f9a6..5728e94b6527b 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1649,7 +1649,6 @@ static irqreturn_t ufs_qcom_mcq_esi_handler(int irq, void *data) struct msi_desc *desc = data; struct device *dev = msi_desc_to_dev(desc); struct ufs_hba *hba = dev_get_drvdata(dev); - struct ufs_qcom_host *host = ufshcd_get_variant(hba); u32 id = desc->msi_index; struct ufs_hw_queue *hwq = &hba->uhq[id]; -- GitLab From 89e637c19b2441aabc8dbf22a8745b932fd6996e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 24 Jul 2023 13:08:30 -0700 Subject: [PATCH 0404/3445] scsi: RDMA/srp: Fix residual handling Although the code for residual handling in the SRP initiator follows the SCSI documentation, that documentation has never been correct. Because scsi_finish_command() starts from the data buffer length and subtracts the residual, scsi_set_resid() must not be called if a residual overflow occurs. Hence remove the scsi_set_resid() calls from the SRP initiator if a residual overflow occurrs. Cc: Leon Romanovsky Cc: Jason Gunthorpe Fixes: 9237f04e12cc ("scsi: core: Fix scsi_get/set_resid() interface") Fixes: e714531a349f ("IB/srp: Fix residual handling") Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20230724200843.3376570-3-bvanassche@acm.org Acked-by: Leon Romanovsky Signed-off-by: Martin K. Petersen --- drivers/infiniband/ulp/srp/ib_srp.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 0e513a7e5ac80..1574218764e0a 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1979,12 +1979,8 @@ static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp) if (unlikely(rsp->flags & SRP_RSP_FLAG_DIUNDER)) scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt)); - else if (unlikely(rsp->flags & SRP_RSP_FLAG_DIOVER)) - scsi_set_resid(scmnd, -be32_to_cpu(rsp->data_in_res_cnt)); else if (unlikely(rsp->flags & SRP_RSP_FLAG_DOUNDER)) scsi_set_resid(scmnd, be32_to_cpu(rsp->data_out_res_cnt)); - else if (unlikely(rsp->flags & SRP_RSP_FLAG_DOOVER)) - scsi_set_resid(scmnd, -be32_to_cpu(rsp->data_out_res_cnt)); srp_free_req(ch, req, scmnd, be32_to_cpu(rsp->req_lim_delta)); -- GitLab From 2903265e27bfc6dea915dd9e17a1b2587f621f73 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 24 Jul 2023 13:08:29 -0700 Subject: [PATCH 0405/3445] scsi: ufs: Fix residual handling Only call scsi_set_resid() in case of an underflow. Do not call scsi_set_resid() in case of an overflow. Cc: Avri Altman Cc: Adrian Hunter Fixes: cb38845d90fc ("scsi: ufs: core: Set the residual byte count") Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20230724200843.3376570-2-bvanassche@acm.org Reviewed-by: Avri Altman Reviewed-by: Adrian Hunter Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 12 ++++++++++-- include/ufs/ufs.h | 6 ++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index c394dc50504ad..27e1a4914837c 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -5222,9 +5222,17 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, int result = 0; int scsi_status; enum utp_ocs ocs; + u8 upiu_flags; + u32 resid; - scsi_set_resid(lrbp->cmd, - be32_to_cpu(lrbp->ucd_rsp_ptr->sr.residual_transfer_count)); + upiu_flags = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_0) >> 16; + resid = be32_to_cpu(lrbp->ucd_rsp_ptr->sr.residual_transfer_count); + /* + * Test !overflow instead of underflow to support UFS devices that do + * not set either flag. + */ + if (resid && !(upiu_flags & UPIU_RSP_FLAG_OVERFLOW)) + scsi_set_resid(lrbp->cmd, resid); /* overall command status of utrd */ ocs = ufshcd_get_tr_ocs(lrbp, cqe); diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h index 0dd546a20503b..c789252b5fad2 100644 --- a/include/ufs/ufs.h +++ b/include/ufs/ufs.h @@ -104,6 +104,12 @@ enum { UPIU_CMD_FLAGS_READ = 0x40, }; +/* UPIU response flags */ +enum { + UPIU_RSP_FLAG_UNDERFLOW = 0x20, + UPIU_RSP_FLAG_OVERFLOW = 0x40, +}; + /* UPIU Task Attributes */ enum { UPIU_TASK_ATTR_SIMPLE = 0x00, -- GitLab From 971dfcb74a800047952f5288512b9c7ddedb050a Mon Sep 17 00:00:00 2001 From: Lin Ma Date: Tue, 25 Jul 2023 10:45:29 +0800 Subject: [PATCH 0406/3445] scsi: iscsi: Add length check for nlattr payload The current NETLINK_ISCSI netlink parsing loop checks every nlmsg to make sure the length is bigger than sizeof(struct iscsi_uevent) and then calls iscsi_if_recv_msg(). nlh = nlmsg_hdr(skb); if (nlh->nlmsg_len < sizeof(*nlh) + sizeof(*ev) || skb->len < nlh->nlmsg_len) { break; } ... err = iscsi_if_recv_msg(skb, nlh, &group); Hence, in iscsi_if_recv_msg() the nlmsg_data can be safely converted to iscsi_uevent as the length is already checked. However, in other cases the length of nlattr payload is not checked before the payload is converted to other data structures. One example is iscsi_set_path() which converts the payload to type iscsi_path without any checks: params = (struct iscsi_path *)((char *)ev + sizeof(*ev)); Whereas iscsi_if_transport_conn() correctly checks the pdu_len: pdu_len = nlh->nlmsg_len - sizeof(*nlh) - sizeof(*ev); if ((ev->u.send_pdu.hdr_size > pdu_len) .. err = -EINVAL; To sum up, some code paths called in iscsi_if_recv_msg() do not check the length of the data (see below picture) and directly convert the data to another data structure. This could result in an out-of-bound reads and heap dirty data leakage. _________ nlmsg_len(nlh) _______________ / \ +----------+--------------+---------------------------+ | nlmsghdr | iscsi_uevent | data | +----------+--------------+---------------------------+ \ / iscsi_uevent->u.set_param.len Fix the issue by adding the length check before accessing it. To clean up the code, an additional parameter named rlen is added. The rlen is calculated at the beginning of iscsi_if_recv_msg() which avoids duplicated calculation. Fixes: ac20c7bf070d ("[SCSI] iscsi_transport: Added Ping support") Fixes: 43514774ff40 ("[SCSI] iscsi class: Add new NETLINK_ISCSI messages for cnic/bnx2i driver.") Fixes: 1d9bf13a9cf9 ("[SCSI] iscsi class: add iscsi host set param event") Fixes: 01cb225dad8d ("[SCSI] iscsi: add target discvery event to transport class") Fixes: 264faaaa1254 ("[SCSI] iscsi: add transport end point callbacks") Fixes: fd7255f51a13 ("[SCSI] iscsi: add sysfs attrs for uspace sync up") Signed-off-by: Lin Ma Link: https://lore.kernel.org/r/20230725024529.428311-1-linma@zju.edu.cn Reviewed-by: Chris Leech Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_transport_iscsi.c | 72 +++++++++++++++++------------ 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index e527ece12453a..62b24f1c0232f 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -3014,14 +3014,15 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev } static int -iscsi_if_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) +iscsi_if_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev, u32 rlen) { char *data = (char*)ev + sizeof(*ev); struct iscsi_cls_conn *conn; struct iscsi_cls_session *session; int err = 0, value = 0, state; - if (ev->u.set_param.len > PAGE_SIZE) + if (ev->u.set_param.len > rlen || + ev->u.set_param.len > PAGE_SIZE) return -EINVAL; session = iscsi_session_lookup(ev->u.set_param.sid); @@ -3118,7 +3119,7 @@ put_ep: static int iscsi_if_transport_ep(struct iscsi_transport *transport, - struct iscsi_uevent *ev, int msg_type) + struct iscsi_uevent *ev, int msg_type, u32 rlen) { struct iscsi_endpoint *ep; int rc = 0; @@ -3126,7 +3127,10 @@ iscsi_if_transport_ep(struct iscsi_transport *transport, switch (msg_type) { case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST: case ISCSI_UEVENT_TRANSPORT_EP_CONNECT: - rc = iscsi_if_ep_connect(transport, ev, msg_type); + if (rlen < sizeof(struct sockaddr)) + rc = -EINVAL; + else + rc = iscsi_if_ep_connect(transport, ev, msg_type); break; case ISCSI_UEVENT_TRANSPORT_EP_POLL: if (!transport->ep_poll) @@ -3150,12 +3154,15 @@ iscsi_if_transport_ep(struct iscsi_transport *transport, static int iscsi_tgt_dscvr(struct iscsi_transport *transport, - struct iscsi_uevent *ev) + struct iscsi_uevent *ev, u32 rlen) { struct Scsi_Host *shost; struct sockaddr *dst_addr; int err; + if (rlen < sizeof(*dst_addr)) + return -EINVAL; + if (!transport->tgt_dscvr) return -EINVAL; @@ -3176,7 +3183,7 @@ iscsi_tgt_dscvr(struct iscsi_transport *transport, static int iscsi_set_host_param(struct iscsi_transport *transport, - struct iscsi_uevent *ev) + struct iscsi_uevent *ev, u32 rlen) { char *data = (char*)ev + sizeof(*ev); struct Scsi_Host *shost; @@ -3185,7 +3192,8 @@ iscsi_set_host_param(struct iscsi_transport *transport, if (!transport->set_host_param) return -ENOSYS; - if (ev->u.set_host_param.len > PAGE_SIZE) + if (ev->u.set_host_param.len > rlen || + ev->u.set_host_param.len > PAGE_SIZE) return -EINVAL; shost = scsi_host_lookup(ev->u.set_host_param.host_no); @@ -3202,12 +3210,15 @@ iscsi_set_host_param(struct iscsi_transport *transport, } static int -iscsi_set_path(struct iscsi_transport *transport, struct iscsi_uevent *ev) +iscsi_set_path(struct iscsi_transport *transport, struct iscsi_uevent *ev, u32 rlen) { struct Scsi_Host *shost; struct iscsi_path *params; int err; + if (rlen < sizeof(*params)) + return -EINVAL; + if (!transport->set_path) return -ENOSYS; @@ -3267,12 +3278,15 @@ iscsi_set_iface_params(struct iscsi_transport *transport, } static int -iscsi_send_ping(struct iscsi_transport *transport, struct iscsi_uevent *ev) +iscsi_send_ping(struct iscsi_transport *transport, struct iscsi_uevent *ev, u32 rlen) { struct Scsi_Host *shost; struct sockaddr *dst_addr; int err; + if (rlen < sizeof(*dst_addr)) + return -EINVAL; + if (!transport->send_ping) return -ENOSYS; @@ -3770,13 +3784,12 @@ exit_host_stats: } static int iscsi_if_transport_conn(struct iscsi_transport *transport, - struct nlmsghdr *nlh) + struct nlmsghdr *nlh, u32 pdu_len) { struct iscsi_uevent *ev = nlmsg_data(nlh); struct iscsi_cls_session *session; struct iscsi_cls_conn *conn = NULL; struct iscsi_endpoint *ep; - uint32_t pdu_len; int err = 0; switch (nlh->nlmsg_type) { @@ -3861,8 +3874,6 @@ static int iscsi_if_transport_conn(struct iscsi_transport *transport, break; case ISCSI_UEVENT_SEND_PDU: - pdu_len = nlh->nlmsg_len - sizeof(*nlh) - sizeof(*ev); - if ((ev->u.send_pdu.hdr_size > pdu_len) || (ev->u.send_pdu.data_size > (pdu_len - ev->u.send_pdu.hdr_size))) { err = -EINVAL; @@ -3892,6 +3903,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) struct iscsi_internal *priv; struct iscsi_cls_session *session; struct iscsi_endpoint *ep = NULL; + u32 rlen; if (!netlink_capable(skb, CAP_SYS_ADMIN)) return -EPERM; @@ -3911,6 +3923,13 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) portid = NETLINK_CB(skb).portid; + /* + * Even though the remaining payload may not be regarded as nlattr, + * (like address or something else), calculate the remaining length + * here to ease following length checks. + */ + rlen = nlmsg_attrlen(nlh, sizeof(*ev)); + switch (nlh->nlmsg_type) { case ISCSI_UEVENT_CREATE_SESSION: err = iscsi_if_create_session(priv, ep, ev, @@ -3967,7 +3986,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) err = -EINVAL; break; case ISCSI_UEVENT_SET_PARAM: - err = iscsi_if_set_param(transport, ev); + err = iscsi_if_set_param(transport, ev, rlen); break; case ISCSI_UEVENT_CREATE_CONN: case ISCSI_UEVENT_DESTROY_CONN: @@ -3975,7 +3994,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) case ISCSI_UEVENT_START_CONN: case ISCSI_UEVENT_BIND_CONN: case ISCSI_UEVENT_SEND_PDU: - err = iscsi_if_transport_conn(transport, nlh); + err = iscsi_if_transport_conn(transport, nlh, rlen); break; case ISCSI_UEVENT_GET_STATS: err = iscsi_if_get_stats(transport, nlh); @@ -3984,23 +4003,22 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) case ISCSI_UEVENT_TRANSPORT_EP_POLL: case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST: - err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type); + err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type, rlen); break; case ISCSI_UEVENT_TGT_DSCVR: - err = iscsi_tgt_dscvr(transport, ev); + err = iscsi_tgt_dscvr(transport, ev, rlen); break; case ISCSI_UEVENT_SET_HOST_PARAM: - err = iscsi_set_host_param(transport, ev); + err = iscsi_set_host_param(transport, ev, rlen); break; case ISCSI_UEVENT_PATH_UPDATE: - err = iscsi_set_path(transport, ev); + err = iscsi_set_path(transport, ev, rlen); break; case ISCSI_UEVENT_SET_IFACE_PARAMS: - err = iscsi_set_iface_params(transport, ev, - nlmsg_attrlen(nlh, sizeof(*ev))); + err = iscsi_set_iface_params(transport, ev, rlen); break; case ISCSI_UEVENT_PING: - err = iscsi_send_ping(transport, ev); + err = iscsi_send_ping(transport, ev, rlen); break; case ISCSI_UEVENT_GET_CHAP: err = iscsi_get_chap(transport, nlh); @@ -4009,13 +4027,10 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) err = iscsi_delete_chap(transport, ev); break; case ISCSI_UEVENT_SET_FLASHNODE_PARAMS: - err = iscsi_set_flashnode_param(transport, ev, - nlmsg_attrlen(nlh, - sizeof(*ev))); + err = iscsi_set_flashnode_param(transport, ev, rlen); break; case ISCSI_UEVENT_NEW_FLASHNODE: - err = iscsi_new_flashnode(transport, ev, - nlmsg_attrlen(nlh, sizeof(*ev))); + err = iscsi_new_flashnode(transport, ev, rlen); break; case ISCSI_UEVENT_DEL_FLASHNODE: err = iscsi_del_flashnode(transport, ev); @@ -4030,8 +4045,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) err = iscsi_logout_flashnode_sid(transport, ev); break; case ISCSI_UEVENT_SET_CHAP: - err = iscsi_set_chap(transport, ev, - nlmsg_attrlen(nlh, sizeof(*ev))); + err = iscsi_set_chap(transport, ev, rlen); break; case ISCSI_UEVENT_GET_HOST_STATS: err = iscsi_get_host_stats(transport, nlh); -- GitLab From ce51c817008450ef4188471db31639d42d37a5e1 Mon Sep 17 00:00:00 2001 From: Lin Ma Date: Sun, 23 Jul 2023 15:58:20 +0800 Subject: [PATCH 0407/3445] scsi: iscsi: Add strlen() check in iscsi_if_set{_host}_param() The functions iscsi_if_set_param() and iscsi_if_set_host_param() convert an nlattr payload to type char* and then call C string handling functions like sscanf and kstrdup: char *data = (char*)ev + sizeof(*ev); ... sscanf(data, "%d", &value); However, since the nlattr is provided by the user-space program and the nlmsg skb is allocated with GFP_KERNEL instead of GFP_ZERO flag (see netlink_alloc_large_skb() in netlink_sendmsg()), dirty data on the heap can lead to an OOB access for those string handling functions. By investigating how the bug is introduced, we find it is really interesting as the old version parsing code starting from commit fd7255f51a13 ("[SCSI] iscsi: add sysfs attrs for uspace sync up") treated the nlattr as integer bytes instead of string and had length check in iscsi_copy_param(): if (ev->u.set_param.len != sizeof(uint32_t)) BUG(); But, since the commit a54a52caad4b ("[SCSI] iscsi: fixup set/get param functions"), the code treated the nlattr as C string while forgetting to add any strlen checks(), opening the possibility of an OOB access. Fix the potential OOB by adding the strlen() check before accessing the buf. If the data passes this check, all low-level set_param handlers can safely treat this buf as legal C string. Fixes: fd7255f51a13 ("[SCSI] iscsi: add sysfs attrs for uspace sync up") Fixes: 1d9bf13a9cf9 ("[SCSI] iscsi class: add iscsi host set param event") Signed-off-by: Lin Ma Link: https://lore.kernel.org/r/20230723075820.3713119-1-linma@zju.edu.cn Reviewed-by: Chris Leech Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_transport_iscsi.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 62b24f1c0232f..3075b2ddf7a69 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -3030,6 +3030,10 @@ iscsi_if_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev, u if (!conn || !session) return -EINVAL; + /* data will be regarded as NULL-ended string, do length check */ + if (strlen(data) > ev->u.set_param.len) + return -EINVAL; + switch (ev->u.set_param.param) { case ISCSI_PARAM_SESS_RECOVERY_TMO: sscanf(data, "%d", &value); @@ -3203,6 +3207,10 @@ iscsi_set_host_param(struct iscsi_transport *transport, return -ENODEV; } + /* see similar check in iscsi_if_set_param() */ + if (strlen(data) > ev->u.set_host_param.len) + return -EINVAL; + err = transport->set_host_param(shost, ev->u.set_host_param.param, data, ev->u.set_host_param.len); scsi_host_put(shost); -- GitLab From ee0268f230f66cb472df3424f380ea668da2749a Mon Sep 17 00:00:00 2001 From: Lin Ma Date: Sun, 23 Jul 2023 15:59:38 +0800 Subject: [PATCH 0408/3445] scsi: be2iscsi: Add length check when parsing nlattrs beiscsi_iface_set_param() parses nlattr with nla_for_each_attr and assumes every attributes can be viewed as struct iscsi_iface_param_info. This is not true because there is no any nla_policy to validate the attributes passed from the upper function iscsi_set_iface_params(). Add the nla_len check before accessing the nlattr data and return EINVAL if the length check fails. Fixes: 0e43895ec1f4 ("[SCSI] be2iscsi: adding functionality to change network settings using iscsiadm") Signed-off-by: Lin Ma Link: https://lore.kernel.org/r/20230723075938.3713864-1-linma@zju.edu.cn Reviewed-by: Chris Leech Signed-off-by: Martin K. Petersen --- drivers/scsi/be2iscsi/be_iscsi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 8aeaddc93b167..8d374ae863ba2 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -450,6 +450,10 @@ int beiscsi_iface_set_param(struct Scsi_Host *shost, } nla_for_each_attr(attrib, data, dt_len, rm_len) { + /* ignore nla_type as it is never used */ + if (nla_len(attrib) < sizeof(*iface_param)) + return -EINVAL; + iface_param = nla_data(attrib); if (iface_param->param_type != ISCSI_NET_PARAM) -- GitLab From 47cd3770e31df942e2bb925a9a855c79ed0662eb Mon Sep 17 00:00:00 2001 From: Lin Ma Date: Sun, 23 Jul 2023 16:00:53 +0800 Subject: [PATCH 0409/3445] scsi: qla4xxx: Add length check when parsing nlattrs There are three places that qla4xxx parses nlattrs: - qla4xxx_set_chap_entry() - qla4xxx_iface_set_param() - qla4xxx_sysfs_ddb_set_param() and each of them directly converts the nlattr to specific pointer of structure without length checking. This could be dangerous as those attributes are not validated and a malformed nlattr (e.g., length 0) could result in an OOB read that leaks heap dirty data. Add the nla_len check before accessing the nlattr data and return EINVAL if the length check fails. Fixes: 26ffd7b45fe9 ("[SCSI] qla4xxx: Add support to set CHAP entries") Fixes: 1e9e2be3ee03 ("[SCSI] qla4xxx: Add flash node mgmt support") Fixes: 00c31889f751 ("[SCSI] qla4xxx: fix data alignment and use nl helpers") Signed-off-by: Lin Ma Link: https://lore.kernel.org/r/20230723080053.3714534-1-linma@zju.edu.cn Reviewed-by: Chris Leech Signed-off-by: Martin K. Petersen --- drivers/scsi/qla4xxx/ql4_os.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index b2a3988e1e159..675332e49a7b0 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -968,6 +968,11 @@ static int qla4xxx_set_chap_entry(struct Scsi_Host *shost, void *data, int len) memset(&chap_rec, 0, sizeof(chap_rec)); nla_for_each_attr(attr, data, len, rem) { + if (nla_len(attr) < sizeof(*param_info)) { + rc = -EINVAL; + goto exit_set_chap; + } + param_info = nla_data(attr); switch (param_info->param) { @@ -2750,6 +2755,11 @@ qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data, uint32_t len) } nla_for_each_attr(attr, data, len, rem) { + if (nla_len(attr) < sizeof(*iface_param)) { + rval = -EINVAL; + goto exit_init_fw_cb; + } + iface_param = nla_data(attr); if (iface_param->param_type == ISCSI_NET_PARAM) { @@ -8104,6 +8114,11 @@ qla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess, memset((void *)&chap_tbl, 0, sizeof(chap_tbl)); nla_for_each_attr(attr, data, len, rem) { + if (nla_len(attr) < sizeof(*fnode_param)) { + rc = -EINVAL; + goto exit_set_param; + } + fnode_param = nla_data(attr); switch (fnode_param->param) { -- GitLab From a615e93d6cfe70f9fab2cb02c7b11fe9de1c56b5 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 25 Jul 2023 22:15:31 +0800 Subject: [PATCH 0410/3445] scsi: iscsi: Remove unused extern declaration iscsi_lookup_iface() This is not used anymore and can be removed. Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20230725141531.10424-1-yuehaibing@huawei.com Reviewed-by: Chris Leech Signed-off-by: Martin K. Petersen --- include/scsi/scsi_transport_iscsi.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 34c03707fb6ef..fb3399e4cd292 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -472,7 +472,6 @@ extern struct iscsi_iface *iscsi_create_iface(struct Scsi_Host *shost, uint32_t iface_type, uint32_t iface_num, int dd_size); extern void iscsi_destroy_iface(struct iscsi_iface *iface); -extern struct iscsi_iface *iscsi_lookup_iface(int handle); extern char *iscsi_get_port_speed_name(struct Scsi_Host *shost); extern char *iscsi_get_port_state_name(struct Scsi_Host *shost); extern int iscsi_is_session_dev(const struct device *dev); -- GitLab From 92e24e0e57f72e06c2df87116557331fd2d4dda2 Mon Sep 17 00:00:00 2001 From: Jeffery Miller Date: Wed, 26 Jul 2023 02:52:48 +0000 Subject: [PATCH 0411/3445] Input: psmouse - add delay when deactivating for SMBus mode There is a period of time between the psmouse deactivate and the ability to communicate with the SMBus companion. Insert a sleep after the deactivate to account for the delay and ensure the SMBus companion is responsive. Attempting to read from the SMBus companion too quickly was causing the touchpad on machines with an i801_smbus companion to stop working after a sleep/resume cycle. On resume the rmi4_smbus would fail with errors reading the SMBus version number: ``` [5454] i2c_i801:i801_check_post:414: i801_smbus 0000:00:1f.3: No response smbus_result: i2c-0 a=02c f=0000 c=fd BYTE_DATA rd res=-6 rmi4_smbus 0-002c: failed to get SMBus version number! ... rmi4_f01 rmi4-00.fn01: Failed to restore normal operation: -6. rmi4_f01 rmi4-00.fn01: Resume failed with code -6. rmi4_physical rmi4-00: Failed to suspend functions: -6 rmi4_smbus 0-002c: Failed to resume device: -6 ``` In this case the rmi_smb_get_version fails with -ENXIO if it happens too soon after the preceding serio_resume -> psmouse_deactivate call. On boot this issue could cause the touchpad to stay in the limited PS/2 mode. This only reproduced in 1 in 10 boots on the Lenovo T440p. Failures in the log on boot would show up as: ``` psmouse serio1: synaptics: Trying to set up SMBus access [122] i2c_i801:i801_check_post:437: i801_smbus 0000:00:1f.3: No response psmouse serio1: synaptics: SMbus companion is not ready yet ``` Experimentation on the Lenovo T440p showed that a delay of 7-12ms on resume allowed the companion to respond. The 30ms delay in this patch was chosen based on the linux-input message: Link: https://lore.kernel.org/all/BYAPR03MB47572F2C65E52ED673238D41B2439@BYAPR03MB4757.namprd03.prod.outlook.com/ Signed-off-by: Jeffery Miller Link: https://lore.kernel.org/r/20230726025256.81174-1-jefferymiller@google.com Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-smbus.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/input/mouse/psmouse-smbus.c b/drivers/input/mouse/psmouse-smbus.c index 2a2459b1b4f2c..7b13de9799089 100644 --- a/drivers/input/mouse/psmouse-smbus.c +++ b/drivers/input/mouse/psmouse-smbus.c @@ -5,6 +5,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include @@ -118,13 +119,18 @@ static psmouse_ret_t psmouse_smbus_process_byte(struct psmouse *psmouse) return PSMOUSE_FULL_PACKET; } -static int psmouse_smbus_reconnect(struct psmouse *psmouse) +static void psmouse_activate_smbus_mode(struct psmouse_smbus_dev *smbdev) { - struct psmouse_smbus_dev *smbdev = psmouse->private; - - if (smbdev->need_deactivate) - psmouse_deactivate(psmouse); + if (smbdev->need_deactivate) { + psmouse_deactivate(smbdev->psmouse); + /* Give the device time to switch into SMBus mode */ + msleep(30); + } +} +static int psmouse_smbus_reconnect(struct psmouse *psmouse) +{ + psmouse_activate_smbus_mode(psmouse->private); return 0; } @@ -257,8 +263,7 @@ int psmouse_smbus_init(struct psmouse *psmouse, } } - if (need_deactivate) - psmouse_deactivate(psmouse); + psmouse_activate_smbus_mode(smbdev); psmouse->private = smbdev; psmouse->protocol_handler = psmouse_smbus_process_byte; -- GitLab From d534fd9787d5925d9637752410e3ea92ca7f4cfa Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Wed, 26 Jul 2023 10:52:47 +0300 Subject: [PATCH 0412/3445] mtd: spi-nor: spansion: use CLPEF as an alternative to CLSR Infineon S28Hx (SEMPER Octal) and S25FS256T (SEMPER Nano) support Clear Program and Erase Failure Flags (CLPEF, 82h) instead of CLSR(30h). Introduce a new mfr_flag together with the infrastructure to allow manufacturer private data in the core. With this we remove the need to have if checks in the code at runtime and instead set the correct opcodes at probe time. S25Hx (SEMPER QSPI) supports CLSR but it may be disabled by CFR3x[2] while CLPEF is always available. Therefore, the mfr_flag is also applied to S25Hx for safety. Signed-off-by: Takahiro Kuwano Link: https://lore.kernel.org/r/20230726075257.12985-2-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/atmel.c | 8 +++- drivers/mtd/spi-nor/core.c | 23 +++++++---- drivers/mtd/spi-nor/core.h | 4 +- drivers/mtd/spi-nor/issi.c | 4 +- drivers/mtd/spi-nor/macronix.c | 4 +- drivers/mtd/spi-nor/micron-st.c | 4 +- drivers/mtd/spi-nor/spansion.c | 72 ++++++++++++++++++++++++++------- drivers/mtd/spi-nor/sst.c | 8 +++- drivers/mtd/spi-nor/winbond.c | 4 +- drivers/mtd/spi-nor/xilinx.c | 4 +- 10 files changed, 103 insertions(+), 32 deletions(-) diff --git a/drivers/mtd/spi-nor/atmel.c b/drivers/mtd/spi-nor/atmel.c index 656dd80a0be79..58968c1e7d2f8 100644 --- a/drivers/mtd/spi-nor/atmel.c +++ b/drivers/mtd/spi-nor/atmel.c @@ -48,9 +48,11 @@ static const struct spi_nor_locking_ops at25fs_nor_locking_ops = { .is_locked = at25fs_nor_is_locked, }; -static void at25fs_nor_late_init(struct spi_nor *nor) +static int at25fs_nor_late_init(struct spi_nor *nor) { nor->params->locking_ops = &at25fs_nor_locking_ops; + + return 0; } static const struct spi_nor_fixups at25fs_nor_fixups = { @@ -149,9 +151,11 @@ static const struct spi_nor_locking_ops atmel_nor_global_protection_ops = { .is_locked = atmel_nor_is_global_protected, }; -static void atmel_nor_global_protection_late_init(struct spi_nor *nor) +static int atmel_nor_global_protection_late_init(struct spi_nor *nor) { nor->params->locking_ops = &atmel_nor_global_protection_ops; + + return 0; } static const struct spi_nor_fixups atmel_nor_global_protection_fixups = { diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 273258f7e77f3..614960c7d22cc 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -2900,16 +2900,23 @@ static void spi_nor_init_fixup_flags(struct spi_nor *nor) * SFDP standard, or where SFDP tables are not defined at all. * Will replace the spi_nor_manufacturer_init_params() method. */ -static void spi_nor_late_init_params(struct spi_nor *nor) +static int spi_nor_late_init_params(struct spi_nor *nor) { struct spi_nor_flash_parameter *params = nor->params; + int ret; if (nor->manufacturer && nor->manufacturer->fixups && - nor->manufacturer->fixups->late_init) - nor->manufacturer->fixups->late_init(nor); + nor->manufacturer->fixups->late_init) { + ret = nor->manufacturer->fixups->late_init(nor); + if (ret) + return ret; + } - if (nor->info->fixups && nor->info->fixups->late_init) - nor->info->fixups->late_init(nor); + if (nor->info->fixups && nor->info->fixups->late_init) { + ret = nor->info->fixups->late_init(nor); + if (ret) + return ret; + } /* Default method kept for backward compatibility. */ if (!params->set_4byte_addr_mode) @@ -2927,6 +2934,8 @@ static void spi_nor_late_init_params(struct spi_nor *nor) if (nor->info->n_banks > 1) params->bank_size = div64_u64(params->size, nor->info->n_banks); + + return 0; } /** @@ -3085,9 +3094,7 @@ static int spi_nor_init_params(struct spi_nor *nor) spi_nor_init_params_deprecated(nor); } - spi_nor_late_init_params(nor); - - return 0; + return spi_nor_late_init_params(nor); } /** spi_nor_set_octal_dtr() - enable or disable Octal DTR I/O. diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index f2fc2cf78e55e..9217379b9cfef 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -378,6 +378,7 @@ struct spi_nor_otp { * than reading the status register to indicate they * are ready for a new command * @locking_ops: SPI NOR locking methods. + * @priv: flash's private data. */ struct spi_nor_flash_parameter { u64 bank_size; @@ -406,6 +407,7 @@ struct spi_nor_flash_parameter { int (*ready)(struct spi_nor *nor); const struct spi_nor_locking_ops *locking_ops; + void *priv; }; /** @@ -432,7 +434,7 @@ struct spi_nor_fixups { const struct sfdp_parameter_header *bfpt_header, const struct sfdp_bfpt *bfpt); int (*post_sfdp)(struct spi_nor *nor); - void (*late_init)(struct spi_nor *nor); + int (*late_init)(struct spi_nor *nor); }; /** diff --git a/drivers/mtd/spi-nor/issi.c b/drivers/mtd/spi-nor/issi.c index 400e2b42f45af..accdf7aa2bfde 100644 --- a/drivers/mtd/spi-nor/issi.c +++ b/drivers/mtd/spi-nor/issi.c @@ -29,7 +29,7 @@ static const struct spi_nor_fixups is25lp256_fixups = { .post_bfpt = is25lp256_post_bfpt_fixups, }; -static void pm25lv_nor_late_init(struct spi_nor *nor) +static int pm25lv_nor_late_init(struct spi_nor *nor) { struct spi_nor_erase_map *map = &nor->params->erase_map; int i; @@ -38,6 +38,8 @@ static void pm25lv_nor_late_init(struct spi_nor *nor) for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) if (map->erase_type[i].size == 4096) map->erase_type[i].opcode = SPINOR_OP_BE_4K_PMC; + + return 0; } static const struct spi_nor_fixups pm25lv_nor_fixups = { diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c index 04888258e8914..eb149e517c1fe 100644 --- a/drivers/mtd/spi-nor/macronix.c +++ b/drivers/mtd/spi-nor/macronix.c @@ -110,10 +110,12 @@ static void macronix_nor_default_init(struct spi_nor *nor) nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable; } -static void macronix_nor_late_init(struct spi_nor *nor) +static int macronix_nor_late_init(struct spi_nor *nor) { if (!nor->params->set_4byte_addr_mode) nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b; + + return 0; } static const struct spi_nor_fixups macronix_nor_fixups = { diff --git a/drivers/mtd/spi-nor/micron-st.c b/drivers/mtd/spi-nor/micron-st.c index f79e71d99124c..6ad080c52ab5d 100644 --- a/drivers/mtd/spi-nor/micron-st.c +++ b/drivers/mtd/spi-nor/micron-st.c @@ -429,7 +429,7 @@ static void micron_st_nor_default_init(struct spi_nor *nor) nor->params->quad_enable = NULL; } -static void micron_st_nor_late_init(struct spi_nor *nor) +static int micron_st_nor_late_init(struct spi_nor *nor) { struct spi_nor_flash_parameter *params = nor->params; @@ -438,6 +438,8 @@ static void micron_st_nor_late_init(struct spi_nor *nor) if (!params->set_4byte_addr_mode) params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_wren_en4b_ex4b; + + return 0; } static const struct spi_nor_fixups micron_st_nor_fixups = { diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 314667d4b8a89..6b2532ed053c8 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -4,14 +4,17 @@ * Copyright (C) 2014, Freescale Semiconductor, Inc. */ +#include #include #include "core.h" /* flash_info mfr_flag. Used to clear sticky prorietary SR bits. */ #define USE_CLSR BIT(0) +#define USE_CLPEF BIT(1) #define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */ +#define SPINOR_OP_CLPEF 0x82 /* Clear program/erase failure flags */ #define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */ #define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */ #define SPINOR_REG_CYPRESS_VREG 0x00800000 @@ -57,22 +60,32 @@ SPI_MEM_OP_DUMMY(ndummy, 0), \ SPI_MEM_OP_DATA_IN(1, buf, 0)) -#define SPANSION_CLSR_OP \ - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLSR, 0), \ +#define SPANSION_OP(opcode) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 0), \ SPI_MEM_OP_NO_ADDR, \ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) +/** + * struct spansion_nor_params - Spansion private parameters. + * @clsr: Clear Status Register or Clear Program and Erase Failure Flag + * opcode. + */ +struct spansion_nor_params { + u8 clsr; +}; + /** * spansion_nor_clear_sr() - Clear the Status Register. * @nor: pointer to 'struct spi_nor'. */ static void spansion_nor_clear_sr(struct spi_nor *nor) { + const struct spansion_nor_params *priv_params = nor->params->priv; int ret; if (nor->spimem) { - struct spi_mem_op op = SPANSION_CLSR_OP; + struct spi_mem_op op = SPANSION_OP(priv_params->clsr); spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); @@ -528,9 +541,11 @@ static int s25fs256t_post_sfdp_fixup(struct spi_nor *nor) return 0; } -static void s25fs256t_late_init(struct spi_nor *nor) +static int s25fs256t_late_init(struct spi_nor *nor) { cypress_nor_ecc_init(nor); + + return 0; } static struct spi_nor_fixups s25fs256t_fixups = { @@ -586,7 +601,7 @@ static int s25hx_t_post_sfdp_fixup(struct spi_nor *nor) return cypress_nor_get_page_size(nor); } -static void s25hx_t_late_init(struct spi_nor *nor) +static int s25hx_t_late_init(struct spi_nor *nor) { struct spi_nor_flash_parameter *params = nor->params; @@ -598,6 +613,8 @@ static void s25hx_t_late_init(struct spi_nor *nor) /* Replace ready() with multi die version */ if (params->n_dice) params->ready = cypress_nor_sr_ready_and_clear; + + return 0; } static struct spi_nor_fixups s25hx_t_fixups = { @@ -659,10 +676,12 @@ static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor, return cypress_nor_set_addr_mode_nbytes(nor); } -static void s28hx_t_late_init(struct spi_nor *nor) +static int s28hx_t_late_init(struct spi_nor *nor) { nor->params->set_octal_dtr = cypress_nor_set_octal_dtr; cypress_nor_ecc_init(nor); + + return 0; } static const struct spi_nor_fixups s28hx_t_fixups = { @@ -786,47 +805,54 @@ static const struct flash_info spansion_nor_parts[] = { FIXUP_FLAGS(SPI_NOR_4B_OPCODES) }, { "s25fs256t", INFO6(0x342b19, 0x0f0890, 0, 0) PARSE_SFDP + MFR_FLAGS(USE_CLPEF) .fixups = &s25fs256t_fixups }, { "s25hl512t", INFO6(0x342a1a, 0x0f0390, 256 * 1024, 256) PARSE_SFDP - MFR_FLAGS(USE_CLSR) + MFR_FLAGS(USE_CLPEF) .fixups = &s25hx_t_fixups }, { "s25hl01gt", INFO6(0x342a1b, 0x0f0390, 256 * 1024, 512) PARSE_SFDP - MFR_FLAGS(USE_CLSR) + MFR_FLAGS(USE_CLPEF) .fixups = &s25hx_t_fixups }, { "s25hl02gt", INFO6(0x342a1c, 0x0f0090, 0, 0) PARSE_SFDP + MFR_FLAGS(USE_CLPEF) FLAGS(NO_CHIP_ERASE) .fixups = &s25hx_t_fixups }, { "s25hs512t", INFO6(0x342b1a, 0x0f0390, 256 * 1024, 256) PARSE_SFDP - MFR_FLAGS(USE_CLSR) + MFR_FLAGS(USE_CLPEF) .fixups = &s25hx_t_fixups }, { "s25hs01gt", INFO6(0x342b1b, 0x0f0390, 256 * 1024, 512) PARSE_SFDP - MFR_FLAGS(USE_CLSR) + MFR_FLAGS(USE_CLPEF) .fixups = &s25hx_t_fixups }, { "s25hs02gt", INFO6(0x342b1c, 0x0f0090, 0, 0) PARSE_SFDP + MFR_FLAGS(USE_CLPEF) FLAGS(NO_CHIP_ERASE) .fixups = &s25hx_t_fixups }, { "cy15x104q", INFO6(0x042cc2, 0x7f7f7f, 512 * 1024, 1) FLAGS(SPI_NOR_NO_ERASE) }, { "s28hl512t", INFO(0x345a1a, 0, 256 * 1024, 256) PARSE_SFDP + MFR_FLAGS(USE_CLPEF) .fixups = &s28hx_t_fixups, }, { "s28hl01gt", INFO(0x345a1b, 0, 256 * 1024, 512) PARSE_SFDP + MFR_FLAGS(USE_CLPEF) .fixups = &s28hx_t_fixups, }, { "s28hs512t", INFO(0x345b1a, 0, 256 * 1024, 256) PARSE_SFDP + MFR_FLAGS(USE_CLPEF) .fixups = &s28hx_t_fixups, }, { "s28hs01gt", INFO(0x345b1b, 0, 256 * 1024, 512) PARSE_SFDP + MFR_FLAGS(USE_CLPEF) .fixups = &s28hx_t_fixups, }, }; @@ -870,17 +896,35 @@ static int spansion_nor_sr_ready_and_clear(struct spi_nor *nor) return !(nor->bouncebuf[0] & SR_WIP); } -static void spansion_nor_late_init(struct spi_nor *nor) +static int spansion_nor_late_init(struct spi_nor *nor) { - if (nor->params->size > SZ_16M) { + struct spi_nor_flash_parameter *params = nor->params; + struct spansion_nor_params *priv_params; + u8 mfr_flags = nor->info->mfr_flags; + + if (params->size > SZ_16M) { nor->flags |= SNOR_F_4B_OPCODES; /* No small sector erase for 4-byte command set */ nor->erase_opcode = SPINOR_OP_SE; nor->mtd.erasesize = nor->info->sector_size; } - if (nor->info->mfr_flags & USE_CLSR) - nor->params->ready = spansion_nor_sr_ready_and_clear; + if (mfr_flags & (USE_CLSR | USE_CLPEF)) { + priv_params = devm_kmalloc(nor->dev, sizeof(*priv_params), + GFP_KERNEL); + if (!priv_params) + return -ENOMEM; + + if (mfr_flags & USE_CLSR) + priv_params->clsr = SPINOR_OP_CLSR; + else if (mfr_flags & USE_CLPEF) + priv_params->clsr = SPINOR_OP_CLPEF; + + params->priv = priv_params; + params->ready = spansion_nor_sr_ready_and_clear; + } + + return 0; } static const struct spi_nor_fixups spansion_nor_fixups = { diff --git a/drivers/mtd/spi-nor/sst.c b/drivers/mtd/spi-nor/sst.c index 688eb20c763e9..09fdc7023e09a 100644 --- a/drivers/mtd/spi-nor/sst.c +++ b/drivers/mtd/spi-nor/sst.c @@ -49,9 +49,11 @@ static const struct spi_nor_locking_ops sst26vf_nor_locking_ops = { .is_locked = sst26vf_nor_is_locked, }; -static void sst26vf_nor_late_init(struct spi_nor *nor) +static int sst26vf_nor_late_init(struct spi_nor *nor) { nor->params->locking_ops = &sst26vf_nor_locking_ops; + + return 0; } static const struct spi_nor_fixups sst26vf_nor_fixups = { @@ -203,10 +205,12 @@ out: return ret; } -static void sst_nor_late_init(struct spi_nor *nor) +static int sst_nor_late_init(struct spi_nor *nor) { if (nor->info->mfr_flags & SST_WRITE) nor->mtd._write = sst_nor_write; + + return 0; } static const struct spi_nor_fixups sst_nor_fixups = { diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c index 63ba8e3a96f51..cd99c9a1c5688 100644 --- a/drivers/mtd/spi-nor/winbond.c +++ b/drivers/mtd/spi-nor/winbond.c @@ -217,7 +217,7 @@ static const struct spi_nor_otp_ops winbond_nor_otp_ops = { .is_locked = spi_nor_otp_is_locked_sr2, }; -static void winbond_nor_late_init(struct spi_nor *nor) +static int winbond_nor_late_init(struct spi_nor *nor) { struct spi_nor_flash_parameter *params = nor->params; @@ -233,6 +233,8 @@ static void winbond_nor_late_init(struct spi_nor *nor) * from BFPT, if any. */ params->set_4byte_addr_mode = winbond_nor_set_4byte_addr_mode; + + return 0; } static const struct spi_nor_fixups winbond_nor_fixups = { diff --git a/drivers/mtd/spi-nor/xilinx.c b/drivers/mtd/spi-nor/xilinx.c index 7175de8aa336a..00d53eae5ee83 100644 --- a/drivers/mtd/spi-nor/xilinx.c +++ b/drivers/mtd/spi-nor/xilinx.c @@ -155,10 +155,12 @@ static int xilinx_nor_setup(struct spi_nor *nor, return 0; } -static void xilinx_nor_late_init(struct spi_nor *nor) +static int xilinx_nor_late_init(struct spi_nor *nor) { nor->params->setup = xilinx_nor_setup; nor->params->ready = xilinx_nor_sr_ready; + + return 0; } static const struct spi_nor_fixups xilinx_nor_fixups = { -- GitLab From 1e611e104b9acb6310b8c684d5acee0e11ca7bd1 Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Wed, 26 Jul 2023 10:52:48 +0300 Subject: [PATCH 0413/3445] mtd: spi-nor: spansion: preserve CFR2V[7] when writing MEMLAT CFR2V[7] is assigned to Flash's address mode (3- or 4-ybte) and must not be changed when writing MEMLAT (CFR2V[3:0]). CFR2V shall be used in a read, update, write back fashion. Fixes: c3266af101f2 ("mtd: spi-nor: spansion: add support for Cypress Semper flash") Signed-off-by: Takahiro Kuwano Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20230726075257.12985-3-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 6b2532ed053c8..6460d2247bdf1 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -4,6 +4,7 @@ * Copyright (C) 2014, Freescale Semiconductor, Inc. */ +#include #include #include @@ -28,6 +29,7 @@ #define SPINOR_REG_CYPRESS_CFR2 0x3 #define SPINOR_REG_CYPRESS_CFR2V \ (SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR2) +#define SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK GENMASK(3, 0) #define SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24 0xb #define SPINOR_REG_CYPRESS_CFR2_ADRBYT BIT(7) #define SPINOR_REG_CYPRESS_CFR3 0x4 @@ -161,8 +163,18 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor) int ret; u8 addr_mode_nbytes = nor->params->addr_mode_nbytes; + op = (struct spi_mem_op) + CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, + SPINOR_REG_CYPRESS_CFR2V, 0, buf); + + ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); + if (ret) + return ret; + /* Use 24 dummy cycles for memory array reads. */ - *buf = SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24; + *buf &= ~SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK; + *buf |= FIELD_PREP(SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK, + SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24); op = (struct spi_mem_op) CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, SPINOR_REG_CYPRESS_CFR2V, 1, buf); -- GitLab From c0aa05123f116c709c816130ef4e55a6748e5e1a Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Wed, 26 Jul 2023 10:52:49 +0300 Subject: [PATCH 0414/3445] mtd: spi-nor: spansion: prepare octal dtr methods for multi chip support Infineon's multi-chip package (MCP) devices require the octal DTR configuration to be set for each die. Split common code in dedicated methods to ease the octal DDR MCP support addition. Signed-off-by: Takahiro Kuwano Link: https://lore.kernel.org/r/20230726075257.12985-4-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 50 +++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 6460d2247bdf1..51eabddf2b169 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -156,7 +156,7 @@ static int cypress_nor_sr_ready_and_clear(struct spi_nor *nor) return 1; } -static int cypress_nor_octal_dtr_en(struct spi_nor *nor) +static int cypress_nor_set_memlat(struct spi_nor *nor, u64 addr) { struct spi_mem_op op; u8 *buf = nor->bouncebuf; @@ -164,8 +164,7 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor) u8 addr_mode_nbytes = nor->params->addr_mode_nbytes; op = (struct spi_mem_op) - CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, - SPINOR_REG_CYPRESS_CFR2V, 0, buf); + CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, addr, 0, buf); ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); if (ret) @@ -176,8 +175,7 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor) *buf |= FIELD_PREP(SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK, SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24); op = (struct spi_mem_op) - CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, - SPINOR_REG_CYPRESS_CFR2V, 1, buf); + CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, addr, 1, buf); ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); if (ret) @@ -185,13 +183,33 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor) nor->read_dummy = 24; + return 0; +} + +static int cypress_nor_set_octal_dtr_bits(struct spi_nor *nor, u64 addr) +{ + struct spi_mem_op op; + u8 *buf = nor->bouncebuf; + /* Set the octal and DTR enable bits. */ buf[0] = SPINOR_REG_CYPRESS_CFR5_OCT_DTR_EN; op = (struct spi_mem_op) - CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, - SPINOR_REG_CYPRESS_CFR5V, 1, buf); + CYPRESS_NOR_WR_ANY_REG_OP(nor->params->addr_mode_nbytes, + addr, 1, buf); - ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); + return spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); +} + +static int cypress_nor_octal_dtr_en(struct spi_nor *nor) +{ + u8 *buf = nor->bouncebuf; + int ret; + + ret = cypress_nor_set_memlat(nor, SPINOR_REG_CYPRESS_CFR2V); + if (ret) + return ret; + + ret = cypress_nor_set_octal_dtr_bits(nor, SPINOR_REG_CYPRESS_CFR5V); if (ret) return ret; @@ -209,11 +227,10 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor) return 0; } -static int cypress_nor_octal_dtr_dis(struct spi_nor *nor) +static int cypress_nor_set_single_spi_bits(struct spi_nor *nor, u64 addr) { struct spi_mem_op op; u8 *buf = nor->bouncebuf; - int ret; /* * The register is 1-byte wide, but 1-byte transactions are not allowed @@ -223,9 +240,16 @@ static int cypress_nor_octal_dtr_dis(struct spi_nor *nor) buf[0] = SPINOR_REG_CYPRESS_CFR5_OCT_DTR_DS; buf[1] = 0; op = (struct spi_mem_op) - CYPRESS_NOR_WR_ANY_REG_OP(nor->addr_nbytes, - SPINOR_REG_CYPRESS_CFR5V, 2, buf); - ret = spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR); + CYPRESS_NOR_WR_ANY_REG_OP(nor->addr_nbytes, addr, 2, buf); + return spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR); +} + +static int cypress_nor_octal_dtr_dis(struct spi_nor *nor) +{ + u8 *buf = nor->bouncebuf; + int ret; + + ret = cypress_nor_set_single_spi_bits(nor, SPINOR_REG_CYPRESS_CFR5V); if (ret) return ret; -- GitLab From 362f786ea00aa21a19ab4f1f836aa0bf9d0aab88 Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Wed, 26 Jul 2023 10:52:50 +0300 Subject: [PATCH 0415/3445] mtd: spi-nor: spansion: switch set_octal_dtr method to use vreg_offset All the Infineon flashes that currently support octal DTR mode define the optional SCCR SFDP table, thus all retrieve vreg_offset. Switch all the available octal DTR Infineon flashes to use the volatile register offset to set the configuration registers. The goal is to have a single pair of methods for both single/multi-chip package devices. Signed-off-by: Takahiro Kuwano Link: https://lore.kernel.org/r/20230726075257.12985-5-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 51eabddf2b169..94d98b5b0ff1c 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -6,6 +6,7 @@ #include #include +#include #include #include "core.h" @@ -37,8 +38,6 @@ (SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR3) #define SPINOR_REG_CYPRESS_CFR3_PGSZ BIT(4) /* Page size. */ #define SPINOR_REG_CYPRESS_CFR5 0x6 -#define SPINOR_REG_CYPRESS_CFR5V \ - (SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR5) #define SPINOR_REG_CYPRESS_CFR5_BIT6 BIT(6) #define SPINOR_REG_CYPRESS_CFR5_DDR BIT(1) #define SPINOR_REG_CYPRESS_CFR5_OPI BIT(0) @@ -202,14 +201,18 @@ static int cypress_nor_set_octal_dtr_bits(struct spi_nor *nor, u64 addr) static int cypress_nor_octal_dtr_en(struct spi_nor *nor) { + const struct spi_nor_flash_parameter *params = nor->params; u8 *buf = nor->bouncebuf; + u64 addr; int ret; - ret = cypress_nor_set_memlat(nor, SPINOR_REG_CYPRESS_CFR2V); + addr = params->vreg_offset[0] + SPINOR_REG_CYPRESS_CFR2; + ret = cypress_nor_set_memlat(nor, addr); if (ret) return ret; - ret = cypress_nor_set_octal_dtr_bits(nor, SPINOR_REG_CYPRESS_CFR5V); + addr = params->vreg_offset[0] + SPINOR_REG_CYPRESS_CFR5; + ret = cypress_nor_set_octal_dtr_bits(nor, addr); if (ret) return ret; @@ -247,9 +250,11 @@ static int cypress_nor_set_single_spi_bits(struct spi_nor *nor, u64 addr) static int cypress_nor_octal_dtr_dis(struct spi_nor *nor) { u8 *buf = nor->bouncebuf; + u64 addr; int ret; - ret = cypress_nor_set_single_spi_bits(nor, SPINOR_REG_CYPRESS_CFR5V); + addr = nor->params->vreg_offset[0] + SPINOR_REG_CYPRESS_CFR5; + ret = cypress_nor_set_single_spi_bits(nor, addr); if (ret) return ret; @@ -714,7 +719,15 @@ static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor, static int s28hx_t_late_init(struct spi_nor *nor) { - nor->params->set_octal_dtr = cypress_nor_set_octal_dtr; + struct spi_nor_flash_parameter *params = nor->params; + + if (!params->n_dice || !params->vreg_offset) { + dev_err(nor->dev, "%s failed. The volatile register offset could not be retrieved from SFDP.\n", + __func__); + return -EOPNOTSUPP; + } + + params->set_octal_dtr = cypress_nor_set_octal_dtr; cypress_nor_ecc_init(nor); return 0; -- GitLab From 463d7cfd08d8cfe5def3070f2f115d7680433183 Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Wed, 26 Jul 2023 10:52:51 +0300 Subject: [PATCH 0416/3445] mtd: spi-nor: spansion: switch h28hx's ready() to use vreg_offset s28hx is the sole user of cypress_nor_set_octal_dtr, which already uses vreg_offset to set octal DTR. Switch the ready method to use vreg_offset as well. This is a preparation patch. The goal is to use the same s28hx methods for the multi die version of the flash. Signed-off-by: Takahiro Kuwano Link: https://lore.kernel.org/r/20230726075257.12985-6-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 94d98b5b0ff1c..6d8dd800ba65f 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -728,6 +728,7 @@ static int s28hx_t_late_init(struct spi_nor *nor) } params->set_octal_dtr = cypress_nor_set_octal_dtr; + params->ready = cypress_nor_sr_ready_and_clear; cypress_nor_ecc_init(nor); return 0; -- GitLab From 7d896a94bf74ba0cf3a9d16d9cef98062e2017d2 Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Wed, 26 Jul 2023 10:52:52 +0300 Subject: [PATCH 0417/3445] mtd: spi-nor: spansion: add MCP support in set_octal_dtr() Infineon multi-chip package (MCP) devices require the Octal DTR configuraion to be set on each die. We can access to configuration registers in each die by using params->n_dice and params->vreg_offset[] populated from SFDP. Add MCP support in set_octal_dtr(). Signed-off-by: Takahiro Kuwano Link: https://lore.kernel.org/r/20230726075257.12985-7-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 6d8dd800ba65f..b3a710985f84b 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -204,17 +204,19 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor) const struct spi_nor_flash_parameter *params = nor->params; u8 *buf = nor->bouncebuf; u64 addr; - int ret; + int i, ret; - addr = params->vreg_offset[0] + SPINOR_REG_CYPRESS_CFR2; - ret = cypress_nor_set_memlat(nor, addr); - if (ret) - return ret; + for (i = 0; i < params->n_dice; i++) { + addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR2; + ret = cypress_nor_set_memlat(nor, addr); + if (ret) + return ret; - addr = params->vreg_offset[0] + SPINOR_REG_CYPRESS_CFR5; - ret = cypress_nor_set_octal_dtr_bits(nor, addr); - if (ret) - return ret; + addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR5; + ret = cypress_nor_set_octal_dtr_bits(nor, addr); + if (ret) + return ret; + } /* Read flash ID to make sure the switch was successful. */ ret = spi_nor_read_id(nor, nor->addr_nbytes, 3, buf, @@ -249,14 +251,17 @@ static int cypress_nor_set_single_spi_bits(struct spi_nor *nor, u64 addr) static int cypress_nor_octal_dtr_dis(struct spi_nor *nor) { + const struct spi_nor_flash_parameter *params = nor->params; u8 *buf = nor->bouncebuf; u64 addr; - int ret; + int i, ret; - addr = nor->params->vreg_offset[0] + SPINOR_REG_CYPRESS_CFR5; - ret = cypress_nor_set_single_spi_bits(nor, addr); - if (ret) - return ret; + for (i = 0; i < params->n_dice; i++) { + addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR5; + ret = cypress_nor_set_single_spi_bits(nor, addr); + if (ret) + return ret; + } /* Read flash ID to make sure the switch was successful. */ ret = spi_nor_read_id(nor, 0, 0, buf, SNOR_PROTO_1_1_1); -- GitLab From eff9604390d6bb275fff1fd359f8b5e521690efa Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Wed, 26 Jul 2023 10:52:53 +0300 Subject: [PATCH 0418/3445] mtd: spi-nor: spansion: add octal DTR support in RD_ANY_REG_OP S28HS02GT uses RD_ANY_REG_OP to read status of each die. In Octal DTR mode, RD_ANY_REG_OP needs dummy cycles (same as params->rdsr_dummy) and data length should be 2. Signed-off-by: Takahiro Kuwano Link: https://lore.kernel.org/r/20230726075257.12985-8-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index b3a710985f84b..d7aa0a90949ae 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -102,11 +102,17 @@ static void spansion_nor_clear_sr(struct spi_nor *nor) static int cypress_nor_sr_ready_and_clear_reg(struct spi_nor *nor, u64 addr) { + struct spi_nor_flash_parameter *params = nor->params; struct spi_mem_op op = - CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes, addr, + CYPRESS_NOR_RD_ANY_REG_OP(params->addr_mode_nbytes, addr, 0, nor->bouncebuf); int ret; + if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) { + op.dummy.nbytes = params->rdsr_dummy; + op.data.nbytes = 2; + } + ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); if (ret) return ret; -- GitLab From 68a86d18339081a11be86e27fcaf3bc986d8fab7 Mon Sep 17 00:00:00 2001 From: Takahiro Kuwano Date: Wed, 26 Jul 2023 10:52:54 +0300 Subject: [PATCH 0419/3445] mtd: spi-nor: spansion: add support for S28HS02GT Add support for S28HS02GT. Infineon S28HS02GT is a 2Gb, multi-chip package, Octal SPI Flash. Signed-off-by: Takahiro Kuwano Link: https://lore.kernel.org/r/20230726075257.12985-9-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index d7aa0a90949ae..1c5671a3751a7 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -693,22 +693,23 @@ static int cypress_nor_set_octal_dtr(struct spi_nor *nor, bool enable) static int s28hx_t_post_sfdp_fixup(struct spi_nor *nor) { + struct spi_nor_flash_parameter *params = nor->params; /* * On older versions of the flash the xSPI Profile 1.0 table has the * 8D-8D-8D Fast Read opcode as 0x00. But it actually should be 0xEE. */ - if (nor->params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode == 0) - nor->params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode = + if (params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode == 0) + params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode = SPINOR_OP_CYPRESS_RD_FAST; /* This flash is also missing the 4-byte Page Program opcode bit. */ - spi_nor_set_pp_settings(&nor->params->page_programs[SNOR_CMD_PP], + spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP], SPINOR_OP_PP_4B, SNOR_PROTO_1_1_1); /* * Since xSPI Page Program opcode is backward compatible with * Legacy SPI, use Legacy SPI opcode there as well. */ - spi_nor_set_pp_settings(&nor->params->page_programs[SNOR_CMD_PP_8_8_8_DTR], + spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_8_8_8_DTR], SPINOR_OP_PP_4B, SNOR_PROTO_8_8_8_DTR); /* @@ -716,7 +717,11 @@ static int s28hx_t_post_sfdp_fixup(struct spi_nor *nor) * address bytes needed for Read Status Register command as 0 but the * actual value for that is 4. */ - nor->params->rdsr_addr_nbytes = 4; + params->rdsr_addr_nbytes = 4; + + /* The 2 Gb parts duplicate info and advertise 4 dice instead of 2. */ + if (params->size == SZ_256M) + params->n_dice = 2; return cypress_nor_get_page_size(nor); } @@ -916,6 +921,11 @@ static const struct flash_info spansion_nor_parts[] = { MFR_FLAGS(USE_CLPEF) .fixups = &s28hx_t_fixups, }, + { "s28hs02gt", INFO(0x345b1c, 0, 0, 0) + PARSE_SFDP + MFR_FLAGS(USE_CLPEF) + .fixups = &s28hx_t_fixups, + }, }; /** -- GitLab From 39133e5f559e748904aeb6b74063882242076a61 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Wed, 26 Jul 2023 10:52:55 +0300 Subject: [PATCH 0420/3445] mtd: spi-nor: spansion: let SFDP determine the flash and sector size sector_size is used to determine the flash size and the erase size in case of uniform erase. n_sectors is used to determine the flash_size. But the flash size and the erase sizes are determined when parsing SFDP, let SFDP determine them. Tested-by: Takahiro Kuwano Link: https://lore.kernel.org/r/20230726075257.12985-10-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 1c5671a3751a7..30a3ffbfa3819 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -873,11 +873,11 @@ static const struct flash_info spansion_nor_parts[] = { PARSE_SFDP MFR_FLAGS(USE_CLPEF) .fixups = &s25fs256t_fixups }, - { "s25hl512t", INFO6(0x342a1a, 0x0f0390, 256 * 1024, 256) + { "s25hl512t", INFO6(0x342a1a, 0x0f0390, 0, 0) PARSE_SFDP MFR_FLAGS(USE_CLPEF) .fixups = &s25hx_t_fixups }, - { "s25hl01gt", INFO6(0x342a1b, 0x0f0390, 256 * 1024, 512) + { "s25hl01gt", INFO6(0x342a1b, 0x0f0390, 0, 0) PARSE_SFDP MFR_FLAGS(USE_CLPEF) .fixups = &s25hx_t_fixups }, @@ -886,11 +886,11 @@ static const struct flash_info spansion_nor_parts[] = { MFR_FLAGS(USE_CLPEF) FLAGS(NO_CHIP_ERASE) .fixups = &s25hx_t_fixups }, - { "s25hs512t", INFO6(0x342b1a, 0x0f0390, 256 * 1024, 256) + { "s25hs512t", INFO6(0x342b1a, 0x0f0390, 0, 0) PARSE_SFDP MFR_FLAGS(USE_CLPEF) .fixups = &s25hx_t_fixups }, - { "s25hs01gt", INFO6(0x342b1b, 0x0f0390, 256 * 1024, 512) + { "s25hs01gt", INFO6(0x342b1b, 0x0f0390, 0, 0) PARSE_SFDP MFR_FLAGS(USE_CLPEF) .fixups = &s25hx_t_fixups }, @@ -901,22 +901,22 @@ static const struct flash_info spansion_nor_parts[] = { .fixups = &s25hx_t_fixups }, { "cy15x104q", INFO6(0x042cc2, 0x7f7f7f, 512 * 1024, 1) FLAGS(SPI_NOR_NO_ERASE) }, - { "s28hl512t", INFO(0x345a1a, 0, 256 * 1024, 256) + { "s28hl512t", INFO(0x345a1a, 0, 0, 0) PARSE_SFDP MFR_FLAGS(USE_CLPEF) .fixups = &s28hx_t_fixups, }, - { "s28hl01gt", INFO(0x345a1b, 0, 256 * 1024, 512) + { "s28hl01gt", INFO(0x345a1b, 0, 0, 0) PARSE_SFDP MFR_FLAGS(USE_CLPEF) .fixups = &s28hx_t_fixups, }, - { "s28hs512t", INFO(0x345b1a, 0, 256 * 1024, 256) + { "s28hs512t", INFO(0x345b1a, 0, 0, 0) PARSE_SFDP MFR_FLAGS(USE_CLPEF) .fixups = &s28hx_t_fixups, }, - { "s28hs01gt", INFO(0x345b1b, 0, 256 * 1024, 512) + { "s28hs01gt", INFO(0x345b1b, 0, 0, 0) PARSE_SFDP MFR_FLAGS(USE_CLPEF) .fixups = &s28hx_t_fixups, -- GitLab From fb63bfad1e8f9f893c2bd5fa3eecb92aa632a3e8 Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Wed, 26 Jul 2023 10:52:56 +0300 Subject: [PATCH 0421/3445] mtd: spi-nor: spansion: switch s25hx_t to use vreg_offset for quad_enable() All s25hx_t flashes have single or multi chip flavors and already use n_dice and vreg_offset in cypress_nor_sr_ready_and_clear. Switch s25hx_t to always use vreg_offset for the quad_enable() method, so that we use the same code base for both single and multi chip package flashes. Tested-by: Takahiro Kuwano Link: https://lore.kernel.org/r/20230726075257.12985-11-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 30a3ffbfa3819..6abef5b515a19 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -24,8 +24,6 @@ #define SPINOR_REG_CYPRESS_STR1V \ (SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_STR1) #define SPINOR_REG_CYPRESS_CFR1 0x2 -#define SPINOR_REG_CYPRESS_CFR1V \ - (SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR1) #define SPINOR_REG_CYPRESS_CFR1_QUAD_EN BIT(1) /* Quad Enable */ #define SPINOR_REG_CYPRESS_CFR2 0x3 #define SPINOR_REG_CYPRESS_CFR2V \ @@ -348,10 +346,6 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor) u8 i; int ret; - if (!params->n_dice) - return cypress_nor_quad_enable_volatile_reg(nor, - SPINOR_REG_CYPRESS_CFR1V); - for (i = 0; i < params->n_dice; i++) { addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR1; ret = cypress_nor_quad_enable_volatile_reg(nor, addr); @@ -657,15 +651,17 @@ static int s25hx_t_late_init(struct spi_nor *nor) { struct spi_nor_flash_parameter *params = nor->params; + if (!params->n_dice || !params->vreg_offset) { + dev_err(nor->dev, "%s failed. The volatile register offset could not be retrieved from SFDP.\n", + __func__); + return -EOPNOTSUPP; + } + /* Fast Read 4B requires mode cycles */ params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8; - + params->ready = cypress_nor_sr_ready_and_clear; cypress_nor_ecc_init(nor); - /* Replace ready() with multi die version */ - if (params->n_dice) - params->ready = cypress_nor_sr_ready_and_clear; - return 0; } -- GitLab From aa517a29d6457e8afcbe8e7e9eb8813594c39d1f Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Wed, 26 Jul 2023 10:52:57 +0300 Subject: [PATCH 0422/3445] mtd: spi-nor: spansion: switch cypress_nor_get_page_size() to use vreg_offset All users of cypress_nor_get_page_size() but S25FS256T retrieve n_dice and vreg_offset from SFDP. S25FS256T does not define the SCCR map to retrive the vreg_offset, but it does support it: SPINOR_REG_CYPRESS_VREG. Switch cypress_nor_get_page_size() to always use vreg_offset so that we use the same code base for both single and multi chip package flashes. cypress_nor_get_page_size() is now called in the post_sfdp() hook instead of post_bfpt(), as vreg_offset and n_dice are parsed after BFPT. Consequently the null checks on n_dice and vreg_offset are moved to the post_sfdp() hook. Tested-by: Takahiro Kuwano Link: https://lore.kernel.org/r/20230726075257.12985-12-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus --- drivers/mtd/spi-nor/spansion.c | 113 ++++++++++++++------------------- 1 file changed, 48 insertions(+), 65 deletions(-) diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 6abef5b515a19..a23eb2ae94888 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -32,8 +32,6 @@ #define SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24 0xb #define SPINOR_REG_CYPRESS_CFR2_ADRBYT BIT(7) #define SPINOR_REG_CYPRESS_CFR3 0x4 -#define SPINOR_REG_CYPRESS_CFR3V \ - (SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR3) #define SPINOR_REG_CYPRESS_CFR3_PGSZ BIT(4) /* Page size. */ #define SPINOR_REG_CYPRESS_CFR5 0x6 #define SPINOR_REG_CYPRESS_CFR5_BIT6 BIT(6) @@ -467,28 +465,17 @@ static int cypress_nor_set_addr_mode_nbytes(struct spi_nor *nor) return 0; } -static int cypress_nor_get_page_size_single_chip(struct spi_nor *nor) -{ - struct spi_mem_op op = - CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes, - SPINOR_REG_CYPRESS_CFR3V, 0, - nor->bouncebuf); - int ret; - - ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); - if (ret) - return ret; - - if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR3_PGSZ) - nor->params->page_size = 512; - else - nor->params->page_size = 256; - - return 0; -} - - -static int cypress_nor_get_page_size_mcp(struct spi_nor *nor) +/** + * cypress_nor_get_page_size() - Get flash page size configuration. + * @nor: pointer to a 'struct spi_nor' + * + * The BFPT table advertises a 512B or 256B page size depending on part but the + * page size is actually configurable (with the default being 256B). Read from + * CFR3V[4] and set the correct size. + * + * Return: 0 on success, -errno otherwise. + */ +static int cypress_nor_get_page_size(struct spi_nor *nor) { struct spi_mem_op op = CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes, @@ -518,23 +505,6 @@ static int cypress_nor_get_page_size_mcp(struct spi_nor *nor) return 0; } -/** - * cypress_nor_get_page_size() - Get flash page size configuration. - * @nor: pointer to a 'struct spi_nor' - * - * The BFPT table advertises a 512B or 256B page size depending on part but the - * page size is actually configurable (with the default being 256B). Read from - * CFR3V[4] and set the correct size. - * - * Return: 0 on success, -errno otherwise. - */ -static int cypress_nor_get_page_size(struct spi_nor *nor) -{ - if (nor->params->n_dice) - return cypress_nor_get_page_size_mcp(nor); - return cypress_nor_get_page_size_single_chip(nor); -} - static void cypress_nor_ecc_init(struct spi_nor *nor) { /* @@ -571,20 +541,32 @@ s25fs256t_post_bfpt_fixup(struct spi_nor *nor, if (nor->bouncebuf[0]) return -ENODEV; - return cypress_nor_get_page_size(nor); + return 0; } static int s25fs256t_post_sfdp_fixup(struct spi_nor *nor) { struct spi_nor_flash_parameter *params = nor->params; + /* + * S25FS256T does not define the SCCR map, but we would like to use the + * same code base for both single and multi chip package devices, thus + * set the vreg_offset and n_dice to be able to do so. + */ + params->vreg_offset = devm_kmalloc(nor->dev, sizeof(u32), GFP_KERNEL); + if (!params->vreg_offset) + return -ENOMEM; + + params->vreg_offset[0] = SPINOR_REG_CYPRESS_VREG; + params->n_dice = 1; + /* PP_1_1_4_4B is supported but missing in 4BAIT. */ params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4; spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_1_1_4], SPINOR_OP_PP_1_1_4_4B, SNOR_PROTO_1_1_4); - return 0; + return cypress_nor_get_page_size(nor); } static int s25fs256t_late_init(struct spi_nor *nor) @@ -619,10 +601,20 @@ s25hx_t_post_bfpt_fixup(struct spi_nor *nor, static int s25hx_t_post_sfdp_fixup(struct spi_nor *nor) { - struct spi_nor_erase_type *erase_type = - nor->params->erase_map.erase_type; + struct spi_nor_flash_parameter *params = nor->params; + struct spi_nor_erase_type *erase_type = params->erase_map.erase_type; unsigned int i; + if (!params->n_dice || !params->vreg_offset) { + dev_err(nor->dev, "%s failed. The volatile register offset could not be retrieved from SFDP.\n", + __func__); + return -EOPNOTSUPP; + } + + /* The 2 Gb parts duplicate info and advertise 4 dice instead of 2. */ + if (params->size == SZ_256M) + params->n_dice = 2; + /* * In some parts, 3byte erase opcodes are advertised by 4BAIT. * Convert them to 4byte erase opcodes. @@ -640,10 +632,6 @@ static int s25hx_t_post_sfdp_fixup(struct spi_nor *nor) } } - /* The 2 Gb parts duplicate info and advertise 4 dice instead of 2. */ - if (nor->params->size == SZ_256M) - nor->params->n_dice = 2; - return cypress_nor_get_page_size(nor); } @@ -651,12 +639,6 @@ static int s25hx_t_late_init(struct spi_nor *nor) { struct spi_nor_flash_parameter *params = nor->params; - if (!params->n_dice || !params->vreg_offset) { - dev_err(nor->dev, "%s failed. The volatile register offset could not be retrieved from SFDP.\n", - __func__); - return -EOPNOTSUPP; - } - /* Fast Read 4B requires mode cycles */ params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8; params->ready = cypress_nor_sr_ready_and_clear; @@ -690,6 +672,17 @@ static int cypress_nor_set_octal_dtr(struct spi_nor *nor, bool enable) static int s28hx_t_post_sfdp_fixup(struct spi_nor *nor) { struct spi_nor_flash_parameter *params = nor->params; + + if (!params->n_dice || !params->vreg_offset) { + dev_err(nor->dev, "%s failed. The volatile register offset could not be retrieved from SFDP.\n", + __func__); + return -EOPNOTSUPP; + } + + /* The 2 Gb parts duplicate info and advertise 4 dice instead of 2. */ + if (params->size == SZ_256M) + params->n_dice = 2; + /* * On older versions of the flash the xSPI Profile 1.0 table has the * 8D-8D-8D Fast Read opcode as 0x00. But it actually should be 0xEE. @@ -715,10 +708,6 @@ static int s28hx_t_post_sfdp_fixup(struct spi_nor *nor) */ params->rdsr_addr_nbytes = 4; - /* The 2 Gb parts duplicate info and advertise 4 dice instead of 2. */ - if (params->size == SZ_256M) - params->n_dice = 2; - return cypress_nor_get_page_size(nor); } @@ -733,12 +722,6 @@ static int s28hx_t_late_init(struct spi_nor *nor) { struct spi_nor_flash_parameter *params = nor->params; - if (!params->n_dice || !params->vreg_offset) { - dev_err(nor->dev, "%s failed. The volatile register offset could not be retrieved from SFDP.\n", - __func__); - return -EOPNOTSUPP; - } - params->set_octal_dtr = cypress_nor_set_octal_dtr; params->ready = cypress_nor_sr_ready_and_clear; cypress_nor_ecc_init(nor); -- GitLab From 8cfc99dada35b8889f76fbe28115dcde1a6f0874 Mon Sep 17 00:00:00 2001 From: Sindhu Devale Date: Tue, 25 Jul 2023 10:55:02 -0500 Subject: [PATCH 0423/3445] RDMA/irdma: Drop a local in irdma_sc_get_next_aeqe Drop the local wqe_idx in irdma_sc_get_next_aeqe and instead store the wqe_idx in the info structure for all asynchronous events(AE) received. There is no reason it should be tied to a specific AE source. Signed-off-by: Sindhu Devale Signed-off-by: Shiraz Saleem Link: https://lore.kernel.org/r/20230725155505.1069-2-shiraz.saleem@intel.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/irdma/ctrl.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/irdma/ctrl.c b/drivers/infiniband/hw/irdma/ctrl.c index d88c9184007ea..b90abdc85057f 100644 --- a/drivers/infiniband/hw/irdma/ctrl.c +++ b/drivers/infiniband/hw/irdma/ctrl.c @@ -4004,7 +4004,6 @@ int irdma_sc_get_next_aeqe(struct irdma_sc_aeq *aeq, { u64 temp, compl_ctx; __le64 *aeqe; - u16 wqe_idx; u8 ae_src; u8 polarity; @@ -4020,7 +4019,7 @@ int irdma_sc_get_next_aeqe(struct irdma_sc_aeq *aeq, aeqe, 16, false); ae_src = (u8)FIELD_GET(IRDMA_AEQE_AESRC, temp); - wqe_idx = (u16)FIELD_GET(IRDMA_AEQE_WQDESCIDX, temp); + info->wqe_idx = (u16)FIELD_GET(IRDMA_AEQE_WQDESCIDX, temp); info->qp_cq_id = (u32)FIELD_GET(IRDMA_AEQE_QPCQID_LOW, temp) | ((u32)FIELD_GET(IRDMA_AEQE_QPCQID_HI, temp) << 18); info->ae_id = (u16)FIELD_GET(IRDMA_AEQE_AECODE, temp); @@ -4103,7 +4102,6 @@ int irdma_sc_get_next_aeqe(struct irdma_sc_aeq *aeq, case IRDMA_AE_SOURCE_RQ_0011: info->qp = true; info->rq = true; - info->wqe_idx = wqe_idx; info->compl_ctx = compl_ctx; break; case IRDMA_AE_SOURCE_CQ: @@ -4117,7 +4115,6 @@ int irdma_sc_get_next_aeqe(struct irdma_sc_aeq *aeq, case IRDMA_AE_SOURCE_SQ_0111: info->qp = true; info->sq = true; - info->wqe_idx = wqe_idx; info->compl_ctx = compl_ctx; break; case IRDMA_AE_SOURCE_IN_RR_WR: -- GitLab From 133b1cba46c6c8b67c630eacc0a1e4969da16517 Mon Sep 17 00:00:00 2001 From: Sindhu Devale Date: Tue, 25 Jul 2023 10:55:03 -0500 Subject: [PATCH 0424/3445] RDMA/irdma: Refactor error handling in create CQP In case of a failure in irdma_create_cqp, do not call irdma_destroy_cqp, but cleanup all the allocated resources in reverse order. Drop the extra argument in irdma_destroy_cqp as its no longer needed. Signed-off-by: Krzysztof Czurylo Signed-off-by: Sindhu Devale Signed-off-by: Shiraz Saleem Link: https://lore.kernel.org/r/20230725155505.1069-3-shiraz.saleem@intel.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/irdma/hw.c | 35 +++++++++++++++++++------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/infiniband/hw/irdma/hw.c b/drivers/infiniband/hw/irdma/hw.c index 795f7fd4f2574..369eb6b6536d7 100644 --- a/drivers/infiniband/hw/irdma/hw.c +++ b/drivers/infiniband/hw/irdma/hw.c @@ -567,7 +567,7 @@ static void irdma_destroy_irq(struct irdma_pci_f *rf, * Issue destroy cqp request and * free the resources associated with the cqp */ -static void irdma_destroy_cqp(struct irdma_pci_f *rf, bool free_hwcqp) +static void irdma_destroy_cqp(struct irdma_pci_f *rf) { struct irdma_sc_dev *dev = &rf->sc_dev; struct irdma_cqp *cqp = &rf->cqp; @@ -575,8 +575,8 @@ static void irdma_destroy_cqp(struct irdma_pci_f *rf, bool free_hwcqp) if (rf->cqp_cmpl_wq) destroy_workqueue(rf->cqp_cmpl_wq); - if (free_hwcqp) - status = irdma_sc_cqp_destroy(dev->cqp); + + status = irdma_sc_cqp_destroy(dev->cqp); if (status) ibdev_dbg(to_ibdev(dev), "ERR: Destroy CQP failed %d\n", status); @@ -920,8 +920,8 @@ static int irdma_create_cqp(struct irdma_pci_f *rf) cqp->scratch_array = kcalloc(sqsize, sizeof(*cqp->scratch_array), GFP_KERNEL); if (!cqp->scratch_array) { - kfree(cqp->cqp_requests); - return -ENOMEM; + status = -ENOMEM; + goto err_scratch; } dev->cqp = &cqp->sc_cqp; @@ -931,15 +931,14 @@ static int irdma_create_cqp(struct irdma_pci_f *rf) cqp->sq.va = dma_alloc_coherent(dev->hw->device, cqp->sq.size, &cqp->sq.pa, GFP_KERNEL); if (!cqp->sq.va) { - kfree(cqp->scratch_array); - kfree(cqp->cqp_requests); - return -ENOMEM; + status = -ENOMEM; + goto err_sq; } status = irdma_obj_aligned_mem(rf, &mem, sizeof(struct irdma_cqp_ctx), IRDMA_HOST_CTX_ALIGNMENT_M); if (status) - goto exit; + goto err_ctx; dev->cqp->host_ctx_pa = mem.pa; dev->cqp->host_ctx = mem.va; @@ -965,7 +964,7 @@ static int irdma_create_cqp(struct irdma_pci_f *rf) status = irdma_sc_cqp_init(dev->cqp, &cqp_init_info); if (status) { ibdev_dbg(to_ibdev(dev), "ERR: cqp init status %d\n", status); - goto exit; + goto err_ctx; } spin_lock_init(&cqp->req_lock); @@ -976,7 +975,7 @@ static int irdma_create_cqp(struct irdma_pci_f *rf) ibdev_dbg(to_ibdev(dev), "ERR: cqp create failed - status %d maj_err %d min_err %d\n", status, maj_err, min_err); - goto exit; + goto err_ctx; } INIT_LIST_HEAD(&cqp->cqp_avail_reqs); @@ -990,8 +989,16 @@ static int irdma_create_cqp(struct irdma_pci_f *rf) init_waitqueue_head(&cqp->remove_wq); return 0; -exit: - irdma_destroy_cqp(rf, false); +err_ctx: + dma_free_coherent(dev->hw->device, cqp->sq.size, + cqp->sq.va, cqp->sq.pa); + cqp->sq.va = NULL; +err_sq: + kfree(cqp->scratch_array); + cqp->scratch_array = NULL; +err_scratch: + kfree(cqp->cqp_requests); + cqp->cqp_requests = NULL; return status; } @@ -1746,7 +1753,7 @@ void irdma_ctrl_deinit_hw(struct irdma_pci_f *rf) rf->reset, rf->rdma_ver); fallthrough; case CQP_CREATED: - irdma_destroy_cqp(rf, true); + irdma_destroy_cqp(rf); fallthrough; case INITIAL_STATE: irdma_del_init_mem(rf); -- GitLab From e49bad785e550fe26ca9416ffc0c85fef84be808 Mon Sep 17 00:00:00 2001 From: Krzysztof Czurylo Date: Tue, 25 Jul 2023 10:55:04 -0500 Subject: [PATCH 0425/3445] RDMA/irdma: Add table based lookup for CQ pointer during an event Add a CQ table based loookup to allow quick search for CQ pointer having CQ ID in case of CQ related asynchrononous event. The table is implemented in a similar fashion to QP table. Also add a reference counters for CQ. This is to prevent destroying CQ while an asynchronous event is being processed. The memory resource table size is sized higher with this update, and this table doesn't need to be physically contiguous, so use a vzalloc vs kzalloc to allocate the table. Signed-off-by: Krzysztof Czurylo Signed-off-by: Sindhu Devale Signed-off-by: Shiraz Saleem Link: https://lore.kernel.org/r/20230725155505.1069-4-shiraz.saleem@intel.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/irdma/hw.c | 27 +++++++++++++++++++-------- drivers/infiniband/hw/irdma/main.h | 4 ++++ drivers/infiniband/hw/irdma/utils.c | 25 +++++++++++++++++++++++++ drivers/infiniband/hw/irdma/verbs.c | 7 +++++++ drivers/infiniband/hw/irdma/verbs.h | 2 ++ 5 files changed, 57 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/hw/irdma/hw.c b/drivers/infiniband/hw/irdma/hw.c index 369eb6b6536d7..8519495d23ce4 100644 --- a/drivers/infiniband/hw/irdma/hw.c +++ b/drivers/infiniband/hw/irdma/hw.c @@ -218,7 +218,6 @@ static void irdma_process_aeq(struct irdma_pci_f *rf) struct irdma_aeqe_info *info = &aeinfo; int ret; struct irdma_qp *iwqp = NULL; - struct irdma_sc_cq *cq = NULL; struct irdma_cq *iwcq = NULL; struct irdma_sc_qp *qp = NULL; struct irdma_qp_host_ctx_info *ctx_info = NULL; @@ -335,10 +334,18 @@ static void irdma_process_aeq(struct irdma_pci_f *rf) ibdev_err(&iwdev->ibdev, "Processing an iWARP related AE for CQ misc = 0x%04X\n", info->ae_id); - cq = (struct irdma_sc_cq *)(unsigned long) - info->compl_ctx; - iwcq = cq->back_cq; + spin_lock_irqsave(&rf->cqtable_lock, flags); + iwcq = rf->cq_table[info->qp_cq_id]; + if (!iwcq) { + spin_unlock_irqrestore(&rf->cqtable_lock, + flags); + ibdev_dbg(to_ibdev(dev), + "cq_id %d is already freed\n", info->qp_cq_id); + continue; + } + irdma_cq_add_ref(&iwcq->ibcq); + spin_unlock_irqrestore(&rf->cqtable_lock, flags); if (iwcq->ibcq.event_handler) { struct ib_event ibevent; @@ -349,6 +356,7 @@ static void irdma_process_aeq(struct irdma_pci_f *rf) iwcq->ibcq.event_handler(&ibevent, iwcq->ibcq.cq_context); } + irdma_cq_rem_ref(&iwcq->ibcq); break; case IRDMA_AE_RESET_NOT_SENT: case IRDMA_AE_LLP_DOUBT_REACHABILITY: @@ -1555,7 +1563,7 @@ static void irdma_del_init_mem(struct irdma_pci_f *rf) kfree(dev->hmc_info->sd_table.sd_entry); dev->hmc_info->sd_table.sd_entry = NULL; - kfree(rf->mem_rsrc); + vfree(rf->mem_rsrc); rf->mem_rsrc = NULL; dma_free_coherent(rf->hw.device, rf->obj_mem.size, rf->obj_mem.va, rf->obj_mem.pa); @@ -1951,10 +1959,12 @@ static void irdma_set_hw_rsrc(struct irdma_pci_f *rf) rf->allocated_arps = &rf->allocated_mcgs[BITS_TO_LONGS(rf->max_mcg)]; rf->qp_table = (struct irdma_qp **) (&rf->allocated_arps[BITS_TO_LONGS(rf->arp_table_size)]); + rf->cq_table = (struct irdma_cq **)(&rf->qp_table[rf->max_qp]); spin_lock_init(&rf->rsrc_lock); spin_lock_init(&rf->arp_lock); spin_lock_init(&rf->qptable_lock); + spin_lock_init(&rf->cqtable_lock); spin_lock_init(&rf->qh_list_lock); } @@ -1975,6 +1985,7 @@ static u32 irdma_calc_mem_rsrc_size(struct irdma_pci_f *rf) rsrc_size += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_ah); rsrc_size += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_mcg); rsrc_size += sizeof(struct irdma_qp **) * rf->max_qp; + rsrc_size += sizeof(struct irdma_cq **) * rf->max_cq; return rsrc_size; } @@ -2008,10 +2019,10 @@ u32 irdma_initialize_hw_rsrc(struct irdma_pci_f *rf) rf->max_mcg = rf->max_qp; rsrc_size = irdma_calc_mem_rsrc_size(rf); - rf->mem_rsrc = kzalloc(rsrc_size, GFP_KERNEL); + rf->mem_rsrc = vzalloc(rsrc_size); if (!rf->mem_rsrc) { ret = -ENOMEM; - goto mem_rsrc_kzalloc_fail; + goto mem_rsrc_vzalloc_fail; } rf->arp_table = (struct irdma_arp_entry *)rf->mem_rsrc; @@ -2039,7 +2050,7 @@ u32 irdma_initialize_hw_rsrc(struct irdma_pci_f *rf) return 0; -mem_rsrc_kzalloc_fail: +mem_rsrc_vzalloc_fail: bitmap_free(rf->allocated_ws_nodes); rf->allocated_ws_nodes = NULL; diff --git a/drivers/infiniband/hw/irdma/main.h b/drivers/infiniband/hw/irdma/main.h index def6dd58dcd48..d3bddd48e8644 100644 --- a/drivers/infiniband/hw/irdma/main.h +++ b/drivers/infiniband/hw/irdma/main.h @@ -309,7 +309,9 @@ struct irdma_pci_f { spinlock_t arp_lock; /*protect ARP table access*/ spinlock_t rsrc_lock; /* protect HW resource array access */ spinlock_t qptable_lock; /*protect QP table access*/ + spinlock_t cqtable_lock; /*protect CQ table access*/ struct irdma_qp **qp_table; + struct irdma_cq **cq_table; spinlock_t qh_list_lock; /* protect mc_qht_list */ struct mc_table_list mc_qht_list; struct irdma_msix_vector *iw_msixtbl; @@ -500,6 +502,8 @@ int irdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, struct ib_udata *udata); int irdma_modify_qp_roce(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, struct ib_udata *udata); +void irdma_cq_add_ref(struct ib_cq *ibcq); +void irdma_cq_rem_ref(struct ib_cq *ibcq); void irdma_cq_wq_destroy(struct irdma_pci_f *rf, struct irdma_sc_cq *cq); void irdma_cleanup_pending_cqp_op(struct irdma_pci_f *rf); diff --git a/drivers/infiniband/hw/irdma/utils.c b/drivers/infiniband/hw/irdma/utils.c index 71e1c5d347092..1008e158bba28 100644 --- a/drivers/infiniband/hw/irdma/utils.c +++ b/drivers/infiniband/hw/irdma/utils.c @@ -760,6 +760,31 @@ void irdma_qp_rem_ref(struct ib_qp *ibqp) complete(&iwqp->free_qp); } +void irdma_cq_add_ref(struct ib_cq *ibcq) +{ + struct irdma_cq *iwcq = to_iwcq(ibcq); + + refcount_inc(&iwcq->refcnt); +} + +void irdma_cq_rem_ref(struct ib_cq *ibcq) +{ + struct ib_device *ibdev = ibcq->device; + struct irdma_device *iwdev = to_iwdev(ibdev); + struct irdma_cq *iwcq = to_iwcq(ibcq); + unsigned long flags; + + spin_lock_irqsave(&iwdev->rf->cqtable_lock, flags); + if (!refcount_dec_and_test(&iwcq->refcnt)) { + spin_unlock_irqrestore(&iwdev->rf->cqtable_lock, flags); + return; + } + + iwdev->rf->cq_table[iwcq->cq_num] = NULL; + spin_unlock_irqrestore(&iwdev->rf->cqtable_lock, flags); + complete(&iwcq->free_cq); +} + struct ib_device *to_ibdev(struct irdma_sc_dev *dev) { return &(container_of(dev, struct irdma_pci_f, sc_dev))->iwdev->ibdev; diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c index a7b82aea4d08e..2009819bfad93 100644 --- a/drivers/infiniband/hw/irdma/verbs.c +++ b/drivers/infiniband/hw/irdma/verbs.c @@ -1805,6 +1805,9 @@ static int irdma_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata) irdma_process_resize_list(iwcq, iwdev, NULL); spin_unlock_irqrestore(&iwcq->lock, flags); + irdma_cq_rem_ref(ib_cq); + wait_for_completion(&iwcq->free_cq); + irdma_cq_wq_destroy(iwdev->rf, cq); spin_lock_irqsave(&iwceq->ce_lock, flags); @@ -2014,6 +2017,7 @@ static int irdma_create_cq(struct ib_cq *ibcq, cq = &iwcq->sc_cq; cq->back_cq = iwcq; + refcount_set(&iwcq->refcnt, 1); spin_lock_init(&iwcq->lock); INIT_LIST_HEAD(&iwcq->resize_list); INIT_LIST_HEAD(&iwcq->cmpl_generated); @@ -2165,6 +2169,9 @@ static int irdma_create_cq(struct ib_cq *ibcq, goto cq_destroy; } } + rf->cq_table[cq_num] = iwcq; + init_completion(&iwcq->free_cq); + return 0; cq_destroy: irdma_cq_wq_destroy(rf, cq); diff --git a/drivers/infiniband/hw/irdma/verbs.h b/drivers/infiniband/hw/irdma/verbs.h index a536e9fa85ebf..9de7217df357d 100644 --- a/drivers/infiniband/hw/irdma/verbs.h +++ b/drivers/infiniband/hw/irdma/verbs.h @@ -122,6 +122,8 @@ struct irdma_cq { u32 cq_mem_size; struct irdma_dma_mem kmem; struct irdma_dma_mem kmem_shadow; + struct completion free_cq; + refcount_t refcnt; spinlock_t lock; /* for poll cq */ struct irdma_pbl *iwpbl; struct irdma_pbl *iwpbl_shadow; -- GitLab From 693e1cdebb50d2aa67406411ca6d5be195d62771 Mon Sep 17 00:00:00 2001 From: Mustafa Ismail Date: Tue, 25 Jul 2023 10:55:05 -0500 Subject: [PATCH 0426/3445] RDMA/irdma: Cleanup and rename irdma_netdev_vlan_ipv6() The return value from irdma_netdev_vlan_ipv6() is not used. Rename the functions and change to a void return. Signed-off-by: Mustafa Ismail Signed-off-by: Shiraz Saleem Link: https://lore.kernel.org/r/20230725155505.1069-5-shiraz.saleem@intel.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/irdma/cm.c | 23 ++++++++++------------- drivers/infiniband/hw/irdma/main.h | 2 +- drivers/infiniband/hw/irdma/verbs.c | 2 +- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/drivers/infiniband/hw/irdma/cm.c b/drivers/infiniband/hw/irdma/cm.c index 70017048d7d18..42d1e97710669 100644 --- a/drivers/infiniband/hw/irdma/cm.c +++ b/drivers/infiniband/hw/irdma/cm.c @@ -1591,21 +1591,20 @@ done: } /** - * irdma_netdev_vlan_ipv6 - Gets the netdev and mac + * irdma_get_vlan_mac_ipv6 - Gets the vlan and mac * @addr: local IPv6 address * @vlan_id: vlan id for the given IPv6 address * @mac: mac address for the given IPv6 address * - * Returns the net_device of the IPv6 address and also sets the - * vlan id and mac for that address. + * Returns the vlan id and mac for an IPv6 address. */ -struct net_device *irdma_netdev_vlan_ipv6(u32 *addr, u16 *vlan_id, u8 *mac) +void irdma_get_vlan_mac_ipv6(u32 *addr, u16 *vlan_id, u8 *mac) { struct net_device *ip_dev = NULL; struct in6_addr laddr6; if (!IS_ENABLED(CONFIG_IPV6)) - return NULL; + return; irdma_copy_ip_htonl(laddr6.in6_u.u6_addr32, addr); if (vlan_id) @@ -1624,8 +1623,6 @@ struct net_device *irdma_netdev_vlan_ipv6(u32 *addr, u16 *vlan_id, u8 *mac) } } rcu_read_unlock(); - - return ip_dev; } /** @@ -3666,8 +3663,8 @@ int irdma_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) cm_node->vlan_id = irdma_get_vlan_ipv4(cm_node->loc_addr); } else { cm_node->ipv4 = false; - irdma_netdev_vlan_ipv6(cm_node->loc_addr, &cm_node->vlan_id, - NULL); + irdma_get_vlan_mac_ipv6(cm_node->loc_addr, &cm_node->vlan_id, + NULL); } ibdev_dbg(&iwdev->ibdev, "CM: Accept vlan_id=%d\n", cm_node->vlan_id); @@ -3875,8 +3872,8 @@ int irdma_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) raddr6->sin6_addr.in6_u.u6_addr32); cm_info.loc_port = ntohs(laddr6->sin6_port); cm_info.rem_port = ntohs(raddr6->sin6_port); - irdma_netdev_vlan_ipv6(cm_info.loc_addr, &cm_info.vlan_id, - NULL); + irdma_get_vlan_mac_ipv6(cm_info.loc_addr, &cm_info.vlan_id, + NULL); } cm_info.cm_id = cm_id; cm_info.qh_qpid = iwdev->vsi.ilq->qp_id; @@ -4005,8 +4002,8 @@ int irdma_create_listen(struct iw_cm_id *cm_id, int backlog) laddr6->sin6_addr.in6_u.u6_addr32); cm_info.loc_port = ntohs(laddr6->sin6_port); if (ipv6_addr_type(&laddr6->sin6_addr) != IPV6_ADDR_ANY) { - irdma_netdev_vlan_ipv6(cm_info.loc_addr, - &cm_info.vlan_id, NULL); + irdma_get_vlan_mac_ipv6(cm_info.loc_addr, + &cm_info.vlan_id, NULL); } else { cm_info.vlan_id = 0xFFFF; wildcard = true; diff --git a/drivers/infiniband/hw/irdma/main.h b/drivers/infiniband/hw/irdma/main.h index d3bddd48e8644..ad2239aabbc59 100644 --- a/drivers/infiniband/hw/irdma/main.h +++ b/drivers/infiniband/hw/irdma/main.h @@ -533,7 +533,7 @@ void irdma_gen_ae(struct irdma_pci_f *rf, struct irdma_sc_qp *qp, void irdma_copy_ip_ntohl(u32 *dst, __be32 *src); void irdma_copy_ip_htonl(__be32 *dst, u32 *src); u16 irdma_get_vlan_ipv4(u32 *addr); -struct net_device *irdma_netdev_vlan_ipv6(u32 *addr, u16 *vlan_id, u8 *mac); +void irdma_get_vlan_mac_ipv6(u32 *addr, u16 *vlan_id, u8 *mac); struct ib_mr *irdma_reg_phys_mr(struct ib_pd *ib_pd, u64 addr, u64 size, int acc, u64 *iova_start); int irdma_upload_qp_context(struct irdma_qp *iwqp, bool freeze, bool raw); diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c index 2009819bfad93..a1a42a7cd7832 100644 --- a/drivers/infiniband/hw/irdma/verbs.c +++ b/drivers/infiniband/hw/irdma/verbs.c @@ -3994,7 +3994,7 @@ static int irdma_attach_mcast(struct ib_qp *ibqp, union ib_gid *ibgid, u16 lid) if (!ipv6_addr_v4mapped((struct in6_addr *)ibgid)) { irdma_copy_ip_ntohl(ip_addr, sgid_addr.saddr_in6.sin6_addr.in6_u.u6_addr32); - irdma_netdev_vlan_ipv6(ip_addr, &vlan_id, NULL); + irdma_get_vlan_mac_ipv6(ip_addr, &vlan_id, NULL); ipv4 = false; ibdev_dbg(&iwdev->ibdev, "VERBS: qp_id=%d, IP6address=%pI6\n", ibqp->qp_num, -- GitLab From e7379477f4478c290be47cde3ad8a39d5ff561d2 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Jul 2023 17:49:27 +0200 Subject: [PATCH 0427/3445] phy: starfive: StarFive PHYs should depend on ARCH_STARFIVE The various StarFive PHYs are only present on StarFive SoCs. Hence add a dependency on ARCH_STARFIVE, to prevent asking the user about these drivers when configuring a kernel without StarFive SoC support. Signed-off-by: Geert Uytterhoeven Acked-by: Changhuang Liang Link: https://lore.kernel.org/r/12097f6107a18e2f7cfb80f47ac7b27808e062c4.1690300076.git.geert+renesas@glider.be Signed-off-by: Vinod Koul --- drivers/phy/starfive/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/phy/starfive/Kconfig b/drivers/phy/starfive/Kconfig index 0508f9b123e0a..9508e21430110 100644 --- a/drivers/phy/starfive/Kconfig +++ b/drivers/phy/starfive/Kconfig @@ -3,6 +3,8 @@ # Phy drivers for StarFive platforms # +if ARCH_STARFIVE || COMPILE_TEST + config PHY_STARFIVE_JH7110_DPHY_RX tristate "StarFive JH7110 D-PHY RX support" depends on HAS_IOMEM @@ -32,3 +34,5 @@ config PHY_STARFIVE_JH7110_USB used with the Cadence USB controller. If M is selected, the module will be called phy-jh7110-usb.ko. + +endif # ARCH_STARFIVE || COMPILE_TEST -- GitLab From 84efbdb7fb8e0844a3f9c67a6bdcc89db1012e1c Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 27 Jun 2023 11:10:18 -0700 Subject: [PATCH 0428/3445] perf parse-events: Remove unused PE_PMU_EVENT_FAKE token Removed by commit 70c90e4a6b2f ("perf parse-events: Avoid scanning PMUs before parsing"). Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: bpf@vger.kernel.org Link: https://lore.kernel.org/r/20230627181030.95608-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.y | 42 ++-------------------------------- 1 file changed, 2 insertions(+), 40 deletions(-) diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 9f28d4b5502f1..64755f9cd6003 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -63,7 +63,7 @@ static void free_list_evsel(struct list_head* list_evsel) %token PE_LEGACY_CACHE %token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP %token PE_ERROR -%token PE_KERNEL_PMU_EVENT PE_PMU_EVENT_FAKE +%token PE_KERNEL_PMU_EVENT %token PE_ARRAY_ALL PE_ARRAY_RANGE %token PE_DRV_CFG_TERM %token PE_TERM_HW @@ -81,7 +81,7 @@ static void free_list_evsel(struct list_head* list_evsel) %type PE_MODIFIER_EVENT %type PE_MODIFIER_BP %type PE_EVENT_NAME -%type PE_KERNEL_PMU_EVENT PE_PMU_EVENT_FAKE +%type PE_KERNEL_PMU_EVENT %type PE_DRV_CFG_TERM %type name_or_raw name_or_legacy %destructor { free ($$); } @@ -394,44 +394,6 @@ PE_KERNEL_PMU_EVENT opt_pmu_config YYABORT; $$ = list; } -| -PE_PMU_EVENT_FAKE sep_dc -{ - struct list_head *list; - int err; - - list = alloc_list(); - if (!list) - YYABORT; - - err = parse_events_add_pmu(_parse_state, list, $1, /*head_config=*/NULL, - /*auto_merge_stats=*/false); - free($1); - if (err < 0) { - free(list); - YYABORT; - } - $$ = list; -} -| -PE_PMU_EVENT_FAKE opt_pmu_config -{ - struct list_head *list; - int err; - - list = alloc_list(); - if (!list) - YYABORT; - - err = parse_events_add_pmu(_parse_state, list, $1, $2, /*auto_merge_stats=*/false); - free($1); - parse_events_terms__delete($2); - if (err < 0) { - free(list); - YYABORT; - } - $$ = list; -} value_sym: PE_VALUE_SYM_HW -- GitLab From bf7d46b3a088ccb8f8045c5902d5848bc23286f9 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 27 Jun 2023 11:10:19 -0700 Subject: [PATCH 0429/3445] perf parse-events: Remove unused PE_KERNEL_PMU_EVENT token Removed by commit 70c90e4a6b2f ("perf parse-events: Avoid scanning PMUs before parsing"). Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: bpf@vger.kernel.org Link: https://lore.kernel.org/r/20230627181030.95608-3-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.y | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 64755f9cd6003..4ee6c68656558 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -63,7 +63,6 @@ static void free_list_evsel(struct list_head* list_evsel) %token PE_LEGACY_CACHE %token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP %token PE_ERROR -%token PE_KERNEL_PMU_EVENT %token PE_ARRAY_ALL PE_ARRAY_RANGE %token PE_DRV_CFG_TERM %token PE_TERM_HW @@ -81,7 +80,6 @@ static void free_list_evsel(struct list_head* list_evsel) %type PE_MODIFIER_EVENT %type PE_MODIFIER_BP %type PE_EVENT_NAME -%type PE_KERNEL_PMU_EVENT %type PE_DRV_CFG_TERM %type name_or_raw name_or_legacy %destructor { free ($$); } @@ -358,18 +356,6 @@ PE_NAME opt_pmu_config #undef CLEANUP_YYABORT } | -PE_KERNEL_PMU_EVENT sep_dc -{ - struct list_head *list; - int err; - - err = parse_events_multi_pmu_add(_parse_state, $1, NULL, &list); - free($1); - if (err < 0) - YYABORT; - $$ = list; -} -| PE_NAME sep_dc { struct list_head *list; @@ -381,19 +367,6 @@ PE_NAME sep_dc YYABORT; $$ = list; } -| -PE_KERNEL_PMU_EVENT opt_pmu_config -{ - struct list_head *list; - int err; - - /* frees $2 */ - err = parse_events_multi_pmu_add(_parse_state, $1, $2, &list); - free($1); - if (err < 0) - YYABORT; - $$ = list; -} value_sym: PE_VALUE_SYM_HW -- GitLab From 7e34daa55051f537036a70bd29b43a4cd4c55564 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 27 Jun 2023 11:10:20 -0700 Subject: [PATCH 0430/3445] perf parse-events: Remove two unused tokens The tokens PE_PREFIX_RAW and PE_PREFIX_GROUP are unused so remove them. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: bpf@vger.kernel.org Link: https://lore.kernel.org/r/20230627181030.95608-4-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 4ee6c68656558..b09a5fa921445 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -61,7 +61,7 @@ static void free_list_evsel(struct list_head* list_evsel) %token PE_BPF_OBJECT PE_BPF_SOURCE %token PE_MODIFIER_EVENT PE_MODIFIER_BP PE_BP_COLON PE_BP_SLASH %token PE_LEGACY_CACHE -%token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP +%token PE_PREFIX_MEM %token PE_ERROR %token PE_ARRAY_ALL PE_ARRAY_RANGE %token PE_DRV_CFG_TERM -- GitLab From 22881e2b458dc75e809fc7798f91f4814f3be65f Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 27 Jun 2023 11:10:21 -0700 Subject: [PATCH 0431/3445] perf parse-events: Add more comments to 'struct parse_events_state' Improve documentation of 'struct parse_events_state'. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: bpf@vger.kernel.org Link: https://lore.kernel.org/r/20230627181030.95608-5-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index b0eb95f93e9c3..b37e5ee193a8f 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -121,17 +121,25 @@ struct parse_events_error { }; struct parse_events_state { + /* The list parsed events are placed on. */ struct list_head list; + /* The updated index used by entries as they are added. */ int idx; + /* Error information. */ struct parse_events_error *error; + /* Used by BPF event creation. */ struct evlist *evlist; + /* Holds returned terms for term parsing. */ struct list_head *terms; + /* Start token. */ int stoken; + /* Special fake PMU marker for testing. */ struct perf_pmu *fake_pmu; /* If non-null, when wildcard matching only match the given PMU. */ const char *pmu_filter; /* Should PE_LEGACY_NAME tokens be generated for config terms? */ bool match_legacy_cache_terms; + /* Were multiple PMUs scanned to find events? */ bool wild_card_pmus; }; -- GitLab From 93d7e9c8fbb4624b7dfe8b3605b9f10f192ede98 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 27 Jun 2023 11:10:22 -0700 Subject: [PATCH 0432/3445] perf parse-events: Avoid regrouped warning for wild card events There is logic to avoid printing the regrouping warning for wild card PMUs, this logic also needs to apply for wild card events. Before: ``` $ perf stat -e '{data_read,data_write}' -a sleep 1 WARNING: events were regrouped to match PMUs Performance counter stats for 'system wide': 2,979.16 MiB data_read 410.26 MiB data_write 1.001541923 seconds time elapsed ``` After: ``` $ perf stat -e '{data_read,data_write}' -a sleep 1 Performance counter stats for 'system wide': 2,975.94 MiB data_read 432.05 MiB data_write 1.001119499 seconds time elapsed ``` Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: bpf@vger.kernel.org Link: https://lore.kernel.org/r/20230627181030.95608-6-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index da29061ecf493..75778d5be5b64 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1730,6 +1730,7 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state, auto_merge_stats)) { pr_debug("%s -> %s/%s/\n", str, pmu->name, alias->str); + parse_state->wild_card_pmus = true; ok++; } parse_events_terms__delete(orig_head); -- GitLab From 350301a3d73b217ab3d87ae42d8fcce2795fe097 Mon Sep 17 00:00:00 2001 From: Arseniy Krasnov Date: Mon, 17 Jul 2023 08:34:00 +0300 Subject: [PATCH 0433/3445] dt-bindings: nand: meson: make ECC properties dependent ECC properties 'nand-ecc-strength' and 'nand-ecc-step-size' depends on each other, so they must be both either set or not set. In first case ECC core will try to use these values if possible (by checking ECC caps provided by driver), in second case ECC core will select most optimal values for both properties. Signed-off-by: Arseniy Krasnov Acked-by: Rob Herring Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230717053402.1203724-2-AVKrasnov@sberdevices.ru --- Documentation/devicetree/bindings/mtd/amlogic,meson-nand.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/mtd/amlogic,meson-nand.yaml b/Documentation/devicetree/bindings/mtd/amlogic,meson-nand.yaml index a98b5d61ea5d5..1c79815e1f7f7 100644 --- a/Documentation/devicetree/bindings/mtd/amlogic,meson-nand.yaml +++ b/Documentation/devicetree/bindings/mtd/amlogic,meson-nand.yaml @@ -66,6 +66,10 @@ patternProperties: unevaluatedProperties: false + dependencies: + nand-ecc-strength: ['nand-ecc-step-size'] + nand-ecc-step-size: ['nand-ecc-strength'] + required: - compatible -- GitLab From 0e1db39336d8be4ddeb9f0d99720056f3ff41310 Mon Sep 17 00:00:00 2001 From: Arseniy Krasnov Date: Mon, 17 Jul 2023 08:34:01 +0300 Subject: [PATCH 0434/3445] mtd: rawnand: meson: support for 512B ECC step size Meson NAND supports both 512B and 1024B ECC step size. Signed-off-by: Arseniy Krasnov Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230717053402.1203724-3-AVKrasnov@sberdevices.ru --- drivers/mtd/nand/raw/meson_nand.c | 45 +++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c index 91eeac49d18fe..9bdea97abe4cc 100644 --- a/drivers/mtd/nand/raw/meson_nand.c +++ b/drivers/mtd/nand/raw/meson_nand.c @@ -135,6 +135,7 @@ struct meson_nfc_nand_chip { struct meson_nand_ecc { u32 bch; u32 strength; + u32 size; }; struct meson_nfc_data { @@ -190,7 +191,8 @@ struct meson_nfc { }; enum { - NFC_ECC_BCH8_1K = 2, + NFC_ECC_BCH8_512 = 1, + NFC_ECC_BCH8_1K, NFC_ECC_BCH24_1K, NFC_ECC_BCH30_1K, NFC_ECC_BCH40_1K, @@ -198,15 +200,16 @@ enum { NFC_ECC_BCH60_1K, }; -#define MESON_ECC_DATA(b, s) { .bch = (b), .strength = (s)} +#define MESON_ECC_DATA(b, s, sz) { .bch = (b), .strength = (s), .size = (sz) } static struct meson_nand_ecc meson_ecc[] = { - MESON_ECC_DATA(NFC_ECC_BCH8_1K, 8), - MESON_ECC_DATA(NFC_ECC_BCH24_1K, 24), - MESON_ECC_DATA(NFC_ECC_BCH30_1K, 30), - MESON_ECC_DATA(NFC_ECC_BCH40_1K, 40), - MESON_ECC_DATA(NFC_ECC_BCH50_1K, 50), - MESON_ECC_DATA(NFC_ECC_BCH60_1K, 60), + MESON_ECC_DATA(NFC_ECC_BCH8_512, 8, 512), + MESON_ECC_DATA(NFC_ECC_BCH8_1K, 8, 1024), + MESON_ECC_DATA(NFC_ECC_BCH24_1K, 24, 1024), + MESON_ECC_DATA(NFC_ECC_BCH30_1K, 30, 1024), + MESON_ECC_DATA(NFC_ECC_BCH40_1K, 40, 1024), + MESON_ECC_DATA(NFC_ECC_BCH50_1K, 50, 1024), + MESON_ECC_DATA(NFC_ECC_BCH60_1K, 60, 1024), }; static int meson_nand_calc_ecc_bytes(int step_size, int strength) @@ -224,8 +227,27 @@ static int meson_nand_calc_ecc_bytes(int step_size, int strength) NAND_ECC_CAPS_SINGLE(meson_gxl_ecc_caps, meson_nand_calc_ecc_bytes, 1024, 8, 24, 30, 40, 50, 60); -NAND_ECC_CAPS_SINGLE(meson_axg_ecc_caps, - meson_nand_calc_ecc_bytes, 1024, 8); + +static const int axg_stepinfo_strengths[] = { 8 }; +static const struct nand_ecc_step_info axg_stepinfo_1024 = { + .stepsize = 1024, + .strengths = axg_stepinfo_strengths, + .nstrengths = ARRAY_SIZE(axg_stepinfo_strengths) +}; + +static const struct nand_ecc_step_info axg_stepinfo_512 = { + .stepsize = 512, + .strengths = axg_stepinfo_strengths, + .nstrengths = ARRAY_SIZE(axg_stepinfo_strengths) +}; + +static const struct nand_ecc_step_info axg_stepinfo[] = { axg_stepinfo_1024, axg_stepinfo_512 }; + +static const struct nand_ecc_caps meson_axg_ecc_caps = { + .stepinfos = axg_stepinfo, + .nstepinfos = ARRAY_SIZE(axg_stepinfo), + .calc_ecc_bytes = meson_nand_calc_ecc_bytes, +}; static struct meson_nfc_nand_chip *to_meson_nand(struct nand_chip *nand) { @@ -1257,7 +1279,8 @@ static int meson_nand_bch_mode(struct nand_chip *nand) return -EINVAL; for (i = 0; i < ARRAY_SIZE(meson_ecc); i++) { - if (meson_ecc[i].strength == nand->ecc.strength) { + if (meson_ecc[i].strength == nand->ecc.strength && + meson_ecc[i].size == nand->ecc.size) { meson_chip->bch_mode = meson_ecc[i].bch; return 0; } -- GitLab From 6680d8b67921fc732a59792dec6d3f94c031451c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 19 Jul 2023 10:43:24 +0200 Subject: [PATCH 0435/3445] mtd: rawnand: brcmnand: propagate init error -EPROBE_DEFER up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MTD subsystem may return -EPROBE_DEFER if something isn't ready yet. It's important to pass that error up so device will get probed later. Signed-off-by: Rafał Miłecki Acked-by: Florian Fainelli Acked-by: William Zhang Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230719084324.14799-1-zajec5@gmail.com --- drivers/mtd/nand/raw/brcmnand/brcmnand.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 39661e23d7d4f..03764b589ec5d 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -3245,6 +3245,10 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc) ret = brcmnand_init_cs(host, NULL); if (ret) { + if (ret == -EPROBE_DEFER) { + of_node_put(child); + goto err; + } devm_kfree(dev, host); continue; /* Try all chip-selects */ } -- GitLab From c2fc6b6947905eee832e9ef445df4803f0056cc6 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Jul 2023 11:47:49 -0600 Subject: [PATCH 0436/3445] mtd: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it was merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Reviewed-by: Linus Walleij Acked-by: Heiko Stuebner Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230714174751.4060439-1-robh@kernel.org --- drivers/mtd/devices/mchp23k256.c | 2 +- drivers/mtd/devices/mchp48l640.c | 2 +- drivers/mtd/devices/mtd_dataflash.c | 1 - drivers/mtd/maps/physmap-bt1-rom.c | 1 - drivers/mtd/maps/physmap-gemini.c | 2 +- drivers/mtd/maps/physmap-ixp4xx.c | 2 +- drivers/mtd/maps/physmap-ixp4xx.h | 1 + drivers/mtd/maps/physmap-versatile.c | 2 +- drivers/mtd/maps/sun_uflash.c | 2 +- drivers/mtd/nand/ecc-mxic.c | 2 +- drivers/mtd/nand/ecc.c | 2 +- drivers/mtd/nand/onenand/onenand_omap2.c | 2 +- drivers/mtd/nand/raw/ams-delta.c | 2 +- drivers/mtd/nand/raw/davinci_nand.c | 1 - drivers/mtd/nand/raw/denali_dt.c | 1 - drivers/mtd/nand/raw/fsl_ifc_nand.c | 1 + drivers/mtd/nand/raw/fsl_upm.c | 3 ++- drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c | 2 +- drivers/mtd/nand/raw/ingenic/ingenic_ecc.c | 1 + drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c | 1 - drivers/mtd/nand/raw/marvell_nand.c | 3 ++- drivers/mtd/nand/raw/meson_nand.c | 1 - drivers/mtd/nand/raw/mpc5121_nfc.c | 4 ++-- drivers/mtd/nand/raw/mtk_nand.c | 1 - drivers/mtd/nand/raw/mxc_nand.c | 1 - drivers/mtd/nand/raw/ndfc.c | 3 ++- drivers/mtd/nand/raw/omap2.c | 2 +- drivers/mtd/nand/raw/pl35x-nand-controller.c | 4 +--- drivers/mtd/nand/raw/qcom_nandc.c | 2 +- drivers/mtd/nand/raw/rockchip-nand-controller.c | 1 - drivers/mtd/nand/raw/s3c2410.c | 1 - drivers/mtd/nand/raw/sh_flctl.c | 1 - drivers/mtd/nand/raw/socrates_nand.c | 3 ++- drivers/mtd/nand/raw/sunxi_nand.c | 1 - drivers/mtd/nand/raw/xway_nand.c | 3 ++- drivers/mtd/spi-nor/controllers/nxp-spifi.c | 1 - 36 files changed, 29 insertions(+), 36 deletions(-) diff --git a/drivers/mtd/devices/mchp23k256.c b/drivers/mtd/devices/mchp23k256.c index 3a6ea7a6a30c3..d533475fda159 100644 --- a/drivers/mtd/devices/mchp23k256.c +++ b/drivers/mtd/devices/mchp23k256.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #define MAX_CMD_SIZE 4 diff --git a/drivers/mtd/devices/mchp48l640.c b/drivers/mtd/devices/mchp48l640.c index 40cd5041174c9..f576e6a890e85 100644 --- a/drivers/mtd/devices/mchp48l640.c +++ b/drivers/mtd/devices/mchp48l640.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include struct mchp48_caps { unsigned int size; diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 1d3b2a94581f1..0c1b933036180 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mtd/maps/physmap-bt1-rom.c b/drivers/mtd/maps/physmap-bt1-rom.c index 58782cfaf71cf..60dccc48f99e0 100644 --- a/drivers/mtd/maps/physmap-bt1-rom.c +++ b/drivers/mtd/maps/physmap-bt1-rom.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mtd/maps/physmap-gemini.c b/drivers/mtd/maps/physmap-gemini.c index d4a46e159d38f..9d3b4bf84a1ad 100644 --- a/drivers/mtd/maps/physmap-gemini.c +++ b/drivers/mtd/maps/physmap-gemini.c @@ -8,10 +8,10 @@ */ #include #include -#include #include #include #include +#include #include #include #include diff --git a/drivers/mtd/maps/physmap-ixp4xx.c b/drivers/mtd/maps/physmap-ixp4xx.c index 6a054229a8a0e..c561468f95f6c 100644 --- a/drivers/mtd/maps/physmap-ixp4xx.c +++ b/drivers/mtd/maps/physmap-ixp4xx.c @@ -11,7 +11,7 @@ */ #include #include -#include +#include #include #include #include "physmap-ixp4xx.h" diff --git a/drivers/mtd/maps/physmap-ixp4xx.h b/drivers/mtd/maps/physmap-ixp4xx.h index b0fc49b7f3edf..46824c57e58a6 100644 --- a/drivers/mtd/maps/physmap-ixp4xx.h +++ b/drivers/mtd/maps/physmap-ixp4xx.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ #include +#include #include #ifdef CONFIG_MTD_PHYSMAP_IXP4XX diff --git a/drivers/mtd/maps/physmap-versatile.c b/drivers/mtd/maps/physmap-versatile.c index a1b8b7b25f88b..8e15d514c82da 100644 --- a/drivers/mtd/maps/physmap-versatile.c +++ b/drivers/mtd/maps/physmap-versatile.c @@ -9,9 +9,9 @@ #include #include #include -#include #include #include +#include #include #include #include "physmap-versatile.h" diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index 860b19f770902..2bfdf1b7e18a1 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/ecc-mxic.c b/drivers/mtd/nand/ecc-mxic.c index 22a760e6024ef..47e10945b8d27 100644 --- a/drivers/mtd/nand/ecc-mxic.c +++ b/drivers/mtd/nand/ecc-mxic.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/ecc.c b/drivers/mtd/nand/ecc.c index 5250764cedee1..8f996e8d61b86 100644 --- a/drivers/mtd/nand/ecc.c +++ b/drivers/mtd/nand/ecc.c @@ -95,9 +95,9 @@ #include #include +#include #include #include -#include #include static LIST_HEAD(on_host_hw_engines); diff --git a/drivers/mtd/nand/onenand/onenand_omap2.c b/drivers/mtd/nand/onenand/onenand_omap2.c index ff7af98604df2..7db53b59605d8 100644 --- a/drivers/mtd/nand/onenand/onenand_omap2.c +++ b/drivers/mtd/nand/onenand/onenand_omap2.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c index fa621ffa64909..919816a7aca75 100644 --- a/drivers/mtd/nand/raw/ams-delta.c +++ b/drivers/mtd/nand/raw/ams-delta.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c index 415d6aaa8255a..e75d81cf8c211 100644 --- a/drivers/mtd/nand/raw/davinci_nand.c +++ b/drivers/mtd/nand/raw/davinci_nand.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mtd/nand/raw/denali_dt.c b/drivers/mtd/nand/raw/denali_dt.c index 915047e3fbc2e..edac8749bb939 100644 --- a/drivers/mtd/nand/raw/denali_dt.c +++ b/drivers/mtd/nand/raw/denali_dt.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mtd/nand/raw/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c index fa537fee67019..20bb1e0cb5ebf 100644 --- a/drivers/mtd/nand/raw/fsl_ifc_nand.c +++ b/drivers/mtd/nand/raw/fsl_ifc_nand.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c index 086426139173f..5bf73efe42e7c 100644 --- a/drivers/mtd/nand/raw/fsl_upm.c +++ b/drivers/mtd/nand/raw/fsl_upm.c @@ -13,7 +13,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index 500e7a28d2e41..e71ad2fcec232 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include "gpmi-nand.h" diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c index 9054559e52dda..525c34c281b65 100644 --- a/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c +++ b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c b/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c index b9f135297aa0b..6748226b8bd12 100644 --- a/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c +++ b/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c index 30c15e4e1cc0d..7d0204ea305bd 100644 --- a/drivers/mtd/nand/raw/marvell_nand.c +++ b/drivers/mtd/nand/raw/marvell_nand.c @@ -77,9 +77,10 @@ #include #include #include -#include +#include #include #include +#include #include #include #include diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c index d3faf80866314..ef821b43b3d48 100644 --- a/drivers/mtd/nand/raw/meson_nand.c +++ b/drivers/mtd/nand/raw/meson_nand.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #define NFC_REG_CMD 0x00 diff --git a/drivers/mtd/nand/raw/mpc5121_nfc.c b/drivers/mtd/nand/raw/mpc5121_nfc.c index ab05ee65702c8..6e8e790f84e74 100644 --- a/drivers/mtd/nand/raw/mpc5121_nfc.c +++ b/drivers/mtd/nand/raw/mpc5121_nfc.c @@ -21,10 +21,10 @@ #include #include #include +#include #include -#include #include -#include +#include #include diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c index b2fa6b2074ab1..b6eb8cb6b5e94 100644 --- a/drivers/mtd/nand/raw/mtk_nand.c +++ b/drivers/mtd/nand/raw/mtk_nand.c @@ -16,7 +16,6 @@ #include #include #include -#include #include /* NAND controller register definition */ diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c index 3d4b2e8294ea6..0cd98d5714fc6 100644 --- a/drivers/mtd/nand/raw/mxc_nand.c +++ b/drivers/mtd/nand/raw/mxc_nand.c @@ -20,7 +20,6 @@ #include #include #include -#include #define DRIVER_NAME "mxc_nand" diff --git a/drivers/mtd/nand/raw/ndfc.c b/drivers/mtd/nand/raw/ndfc.c index 57f3db32122d4..3bb32a7c6d679 100644 --- a/drivers/mtd/nand/raw/ndfc.c +++ b/drivers/mtd/nand/raw/ndfc.c @@ -22,8 +22,9 @@ #include #include #include +#include #include -#include +#include #include #define NDFC_MAX_CS 4 diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c index db22b3af16d8a..e057c03a197d9 100644 --- a/drivers/mtd/nand/raw/omap2.c +++ b/drivers/mtd/nand/raw/omap2.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include diff --git a/drivers/mtd/nand/raw/pl35x-nand-controller.c b/drivers/mtd/nand/raw/pl35x-nand-controller.c index 28b7bd7e22eb4..8da5fee321b57 100644 --- a/drivers/mtd/nand/raw/pl35x-nand-controller.c +++ b/drivers/mtd/nand/raw/pl35x-nand-controller.c @@ -23,9 +23,7 @@ #include #include #include -#include -#include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 72d6168d8a1be..df245353b12b4 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -3,6 +3,7 @@ * Copyright (c) 2016, The Linux Foundation. All rights reserved. */ #include +#include #include #include #include @@ -12,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mtd/nand/raw/rockchip-nand-controller.c b/drivers/mtd/nand/raw/rockchip-nand-controller.c index 2312e27362cbe..0ec03ffb4846f 100644 --- a/drivers/mtd/nand/raw/rockchip-nand-controller.c +++ b/drivers/mtd/nand/raw/rockchip-nand-controller.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mtd/nand/raw/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c index ac80aaf5b4e30..3d3d5c9814ffc 100644 --- a/drivers/mtd/nand/raw/s3c2410.c +++ b/drivers/mtd/nand/raw/s3c2410.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c index 63bf20c417197..08211e96ce642 100644 --- a/drivers/mtd/nand/raw/sh_flctl.c +++ b/drivers/mtd/nand/raw/sh_flctl.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mtd/nand/raw/socrates_nand.c b/drivers/mtd/nand/raw/socrates_nand.c index a8b720ffe9e84..76d50eb9f1db5 100644 --- a/drivers/mtd/nand/raw/socrates_nand.c +++ b/drivers/mtd/nand/raw/socrates_nand.c @@ -8,8 +8,9 @@ #include #include #include +#include #include -#include +#include #include #define FPGA_NAND_CMD_MASK (0x7 << 28) diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index 9884304634f68..c6cd7713bee74 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mtd/nand/raw/xway_nand.c b/drivers/mtd/nand/raw/xway_nand.c index 6b1e2a2bba15c..51d802a165edf 100644 --- a/drivers/mtd/nand/raw/xway_nand.c +++ b/drivers/mtd/nand/raw/xway_nand.c @@ -7,7 +7,8 @@ #include #include -#include +#include +#include #include diff --git a/drivers/mtd/spi-nor/controllers/nxp-spifi.c b/drivers/mtd/spi-nor/controllers/nxp-spifi.c index 794c7b7d5c92b..337e83bf33627 100644 --- a/drivers/mtd/spi-nor/controllers/nxp-spifi.c +++ b/drivers/mtd/spi-nor/controllers/nxp-spifi.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include -- GitLab From d2236f6219fac62ee22d971e06a04148f4eb8cca Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 19 Jul 2023 11:33:54 +0100 Subject: [PATCH 0437/3445] mtdblock: make warning messages ratelimited When exercising various dev interfaces with stress-ng the mtdblock drivers can be (ab)used to generate a lot of warning messages. Make these rate limited to reduce the kernel log from being spammed with the same messages. Signed-off-by: Colin Ian King Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230719103354.2829366-1-colin.i.king@gmail.com --- drivers/mtd/mtdblock.c | 2 +- drivers/mtd/mtdblock_ro.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index fa476fb4dffb6..9751416c2a91b 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -262,7 +262,7 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd) } if (mtd_type_is_nand(mbd->mtd)) - pr_warn("%s: MTD device '%s' is NAND, please consider using UBI block devices instead.\n", + pr_warn_ratelimited("%s: MTD device '%s' is NAND, please consider using UBI block devices instead.\n", mbd->tr->name, mbd->mtd->name); /* OK, it's not open. Create cache info for it */ diff --git a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c index 66ffc9f1ead2f..ef6299af60e4f 100644 --- a/drivers/mtd/mtdblock_ro.c +++ b/drivers/mtd/mtdblock_ro.c @@ -49,7 +49,7 @@ static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) dev->readonly = 1; if (mtd_type_is_nand(mtd)) - pr_warn("%s: MTD device '%s' is NAND, please consider using UBI block devices instead.\n", + pr_warn_ratelimited("%s: MTD device '%s' is NAND, please consider using UBI block devices instead.\n", tr->name, mtd->name); if (add_mtd_blktrans_dev(dev)) -- GitLab From 05117bafbd6cdbd5639d5f02d298731e16444d7c Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 25 Jul 2023 00:24:17 +0200 Subject: [PATCH 0438/3445] dt-bindings: remoteproc: imx_rproc: Support i.MX8MN/P MMIO The MX8M CM7 boot via SMC call is problematic, since not all versions of ATF support this interface. Document MMIO support used to boot the CM7 on MX8MN/MP instead and discern MMIO interface using DT compatible string. Document GPR register syscon phandle which is required by the MMIO interface too. Signed-off-by: Marek Vasut Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230724222418.163220-1-marex@denx.de Signed-off-by: Mathieu Poirier --- .../bindings/remoteproc/fsl,imx-rproc.yaml | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml index 0c3910f152d1d..30632efdad8bb 100644 --- a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml +++ b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml @@ -20,7 +20,9 @@ properties: - fsl,imx7ulp-cm4 - fsl,imx8mm-cm4 - fsl,imx8mn-cm7 + - fsl,imx8mn-cm7-mmio - fsl,imx8mp-cm7 + - fsl,imx8mp-cm7-mmio - fsl,imx8mq-cm4 - fsl,imx8qm-cm4 - fsl,imx8qxp-cm4 @@ -70,6 +72,11 @@ properties: description: Specify CPU entry address for SCU enabled processor. + fsl,iomuxc-gpr: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to IOMUXC GPR block which provide access to CM7 CPUWAIT bit. + fsl,resource-id: $ref: /schemas/types.yaml#/definitions/uint32 description: @@ -79,6 +86,19 @@ properties: required: - compatible +allOf: + - if: + properties: + compatible: + not: + contains: + enum: + - fsl,imx8mn-cm7-mmio + - fsl,imx8mp-cm7-mmio + then: + properties: + fsl,iomuxc-gpr: false + additionalProperties: false examples: -- GitLab From 49f80a7ab988de408518b935c1eab5953c63308e Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 25 Jul 2023 00:24:18 +0200 Subject: [PATCH 0439/3445] remoteproc: imx_rproc: Switch iMX8MN/MP from SMCCC to MMIO The MX8M CM7 boot via SMC call is problematic, since not all versions of ATF support this interface. Extend the MMIO support so it can boot the CM7 on MX8MN/MP instead and discern the two alternatives using DT compatible strings. Signed-off-by: Marek Vasut Reviewed-by: Peng Fan Link: https://lore.kernel.org/r/20230724222418.163220-2-marex@denx.de Signed-off-by: Mathieu Poirier --- drivers/remoteproc/imx_rproc.c | 58 ++++++++++++++++++++++++++++++++-- drivers/remoteproc/imx_rproc.h | 2 ++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 4ee2646ce62ad..8bb293b9f327c 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -40,6 +40,12 @@ #define IMX7D_M4_STOP (IMX7D_ENABLE_M4 | IMX7D_SW_M4C_RST | \ IMX7D_SW_M4C_NON_SCLR_RST) +#define IMX8M_M7_STOP (IMX7D_ENABLE_M4 | IMX7D_SW_M4C_RST) +#define IMX8M_M7_POLL IMX7D_ENABLE_M4 + +#define IMX8M_GPR22 0x58 +#define IMX8M_GPR22_CM7_CPUWAIT BIT(0) + /* Address: 0x020D8000 */ #define IMX6SX_SRC_SCR 0x00 #define IMX6SX_ENABLE_M4 BIT(22) @@ -91,6 +97,7 @@ static int imx_rproc_detach_pd(struct rproc *rproc); struct imx_rproc { struct device *dev; struct regmap *regmap; + struct regmap *gpr; struct rproc *rproc; const struct imx_rproc_dcfg *dcfg; struct imx_rproc_mem mem[IMX_RPROC_MEM_MAX]; @@ -285,6 +292,18 @@ static const struct imx_rproc_att imx_rproc_att_imx6sx[] = { { 0x80000000, 0x80000000, 0x60000000, 0 }, }; +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn_mmio = { + .src_reg = IMX7D_SRC_SCR, + .src_mask = IMX7D_M4_RST_MASK, + .src_start = IMX7D_M4_START, + .src_stop = IMX8M_M7_STOP, + .gpr_reg = IMX8M_GPR22, + .gpr_wait = IMX8M_GPR22_CM7_CPUWAIT, + .att = imx_rproc_att_imx8mn, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn), + .method = IMX_RPROC_MMIO, +}; + static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn = { .att = imx_rproc_att_imx8mn, .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn), @@ -365,8 +384,14 @@ static int imx_rproc_start(struct rproc *rproc) switch (dcfg->method) { case IMX_RPROC_MMIO: - ret = regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, - dcfg->src_start); + if (priv->gpr) { + ret = regmap_clear_bits(priv->gpr, dcfg->gpr_reg, + dcfg->gpr_wait); + } else { + ret = regmap_update_bits(priv->regmap, dcfg->src_reg, + dcfg->src_mask, + dcfg->src_start); + } break; case IMX_RPROC_SMC: arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_START, 0, 0, 0, 0, 0, 0, &res); @@ -395,6 +420,16 @@ static int imx_rproc_stop(struct rproc *rproc) switch (dcfg->method) { case IMX_RPROC_MMIO: + if (priv->gpr) { + ret = regmap_set_bits(priv->gpr, dcfg->gpr_reg, + dcfg->gpr_wait); + if (ret) { + dev_err(priv->dev, + "Failed to quiescence M4 platform!\n"); + return ret; + } + } + ret = regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, dcfg->src_stop); break; @@ -992,6 +1027,10 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv) break; } + priv->gpr = syscon_regmap_lookup_by_phandle(dev->of_node, "fsl,iomuxc-gpr"); + if (IS_ERR(priv->gpr)) + priv->gpr = NULL; + regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); if (IS_ERR(regmap)) { dev_err(dev, "failed to find syscon\n"); @@ -1001,6 +1040,19 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv) priv->regmap = regmap; regmap_attach_dev(dev, regmap, &config); + if (priv->gpr) { + ret = regmap_read(priv->gpr, dcfg->gpr_reg, &val); + if (val & dcfg->gpr_wait) { + /* + * After cold boot, the CM indicates its in wait + * state, but not fully powered off. Power it off + * fully so firmware can be loaded into it. + */ + imx_rproc_stop(priv->rproc); + return 0; + } + } + ret = regmap_read(regmap, dcfg->src_reg, &val); if (ret) { dev_err(dev, "Failed to read src\n"); @@ -1142,6 +1194,8 @@ static const struct of_device_id imx_rproc_of_match[] = { { .compatible = "fsl,imx8mm-cm4", .data = &imx_rproc_cfg_imx8mq }, { .compatible = "fsl,imx8mn-cm7", .data = &imx_rproc_cfg_imx8mn }, { .compatible = "fsl,imx8mp-cm7", .data = &imx_rproc_cfg_imx8mn }, + { .compatible = "fsl,imx8mn-cm7-mmio", .data = &imx_rproc_cfg_imx8mn_mmio }, + { .compatible = "fsl,imx8mp-cm7-mmio", .data = &imx_rproc_cfg_imx8mn_mmio }, { .compatible = "fsl,imx8qxp-cm4", .data = &imx_rproc_cfg_imx8qxp }, { .compatible = "fsl,imx8qm-cm4", .data = &imx_rproc_cfg_imx8qm }, { .compatible = "fsl,imx8ulp-cm33", .data = &imx_rproc_cfg_imx8ulp }, diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h index 1c7e2127c7584..79a1b8956d142 100644 --- a/drivers/remoteproc/imx_rproc.h +++ b/drivers/remoteproc/imx_rproc.h @@ -31,6 +31,8 @@ struct imx_rproc_dcfg { u32 src_mask; u32 src_start; u32 src_stop; + u32 gpr_reg; + u32 gpr_wait; const struct imx_rproc_att *att; size_t att_size; enum imx_rproc_method method; -- GitLab From 31f077c374a8e7cf1960560c0c5e4065048557c0 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:44 -0400 Subject: [PATCH 0440/3445] rtc: pcf2127: improve rtc_read_time() performance Improve performance and readability of rtc_read_time() by reading only the 7 time registers, instead of reading 8 registers (additional CTRL3 register). We drop reading of CTRL3 to monitor the low battery flag, as this check is already available in the ioctl. Anyway, this check only display an info message and has no other impacts. The code readability also improves as we do not have to fiddle with buffer pointer and size arithmetic. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-2-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 42 +++++++++++++-------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index ee03b04b74baa..8d40a413a8fe3 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -45,12 +45,6 @@ /* Time and date registers */ #define PCF2127_REG_SC 0x03 #define PCF2127_BIT_SC_OSF BIT(7) -#define PCF2127_REG_MN 0x04 -#define PCF2127_REG_HR 0x05 -#define PCF2127_REG_DM 0x06 -#define PCF2127_REG_DW 0x07 -#define PCF2127_REG_MO 0x08 -#define PCF2127_REG_YR 0x09 /* Alarm registers */ #define PCF2127_REG_ALARM_SC 0x0A #define PCF2127_REG_ALARM_MN 0x0B @@ -117,27 +111,22 @@ struct pcf2127 { static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct pcf2127 *pcf2127 = dev_get_drvdata(dev); - unsigned char buf[10]; + unsigned char buf[7]; int ret; /* * Avoid reading CTRL2 register as it causes WD_VAL register * value to reset to 0 which means watchdog is stopped. */ - ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL3, - (buf + PCF2127_REG_CTRL3), - ARRAY_SIZE(buf) - PCF2127_REG_CTRL3); + ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_SC, buf, + sizeof(buf)); if (ret) { dev_err(dev, "%s: read error\n", __func__); return ret; } - if (buf[PCF2127_REG_CTRL3] & PCF2127_BIT_CTRL3_BLF) - dev_info(dev, - "low voltage detected, check/replace RTC battery.\n"); - /* Clock integrity is not guaranteed when OSF flag is set. */ - if (buf[PCF2127_REG_SC] & PCF2127_BIT_SC_OSF) { + if (buf[0] & PCF2127_BIT_SC_OSF) { /* * no need clear the flag here, * it will be cleared once the new date is saved @@ -148,20 +137,17 @@ static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) } dev_dbg(dev, - "%s: raw data is cr3=%02x, sec=%02x, min=%02x, hr=%02x, " + "%s: raw data is sec=%02x, min=%02x, hr=%02x, " "mday=%02x, wday=%02x, mon=%02x, year=%02x\n", - __func__, buf[PCF2127_REG_CTRL3], buf[PCF2127_REG_SC], - buf[PCF2127_REG_MN], buf[PCF2127_REG_HR], - buf[PCF2127_REG_DM], buf[PCF2127_REG_DW], - buf[PCF2127_REG_MO], buf[PCF2127_REG_YR]); - - tm->tm_sec = bcd2bin(buf[PCF2127_REG_SC] & 0x7F); - tm->tm_min = bcd2bin(buf[PCF2127_REG_MN] & 0x7F); - tm->tm_hour = bcd2bin(buf[PCF2127_REG_HR] & 0x3F); /* rtc hr 0-23 */ - tm->tm_mday = bcd2bin(buf[PCF2127_REG_DM] & 0x3F); - tm->tm_wday = buf[PCF2127_REG_DW] & 0x07; - tm->tm_mon = bcd2bin(buf[PCF2127_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */ - tm->tm_year = bcd2bin(buf[PCF2127_REG_YR]); + __func__, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); + + tm->tm_sec = bcd2bin(buf[0] & 0x7F); + tm->tm_min = bcd2bin(buf[1] & 0x7F); + tm->tm_hour = bcd2bin(buf[2] & 0x3F); /* rtc hr 0-23 */ + tm->tm_mday = bcd2bin(buf[3] & 0x3F); + tm->tm_wday = buf[4] & 0x07; + tm->tm_mon = bcd2bin(buf[5] & 0x1F) - 1; /* rtc mn 1-12 */ + tm->tm_year = bcd2bin(buf[6]); tm->tm_year += 100; dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " -- GitLab From 720fb4b83b565c7ae31059620e960ecbf5dc73a3 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:45 -0400 Subject: [PATCH 0441/3445] rtc: pcf2127: improve timestamp reading performance Reading the 7 timetamp registers currently involves reading 25 registers solely to be able to print the content of the three control registers, in addition to the 7 timestamp registers. This print never occurs, unless the user enables dynamic debug in this driver or set CONFIG_RTC_DEBUG. Reading the timestamp registers should consist of reading 7 consecutive timestamp registers. This patch optimize the performance of reading the timestamp registers by reading 7 consecutive registers instead of 25, and dropping the print of the control registers. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-3-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 8d40a413a8fe3..3332d26aee118 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -66,12 +66,6 @@ #define PCF2127_REG_TS_CTRL 0x12 #define PCF2127_BIT_TS_CTRL_TSOFF BIT(6) #define PCF2127_BIT_TS_CTRL_TSM BIT(7) -#define PCF2127_REG_TS_SC 0x13 -#define PCF2127_REG_TS_MN 0x14 -#define PCF2127_REG_TS_HR 0x15 -#define PCF2127_REG_TS_DM 0x16 -#define PCF2127_REG_TS_MO 0x17 -#define PCF2127_REG_TS_YR 0x18 /* * RAM registers * PCF2127 has 512 bytes general-purpose static RAM (SRAM) that is @@ -440,9 +434,9 @@ static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts) struct pcf2127 *pcf2127 = dev_get_drvdata(dev); struct rtc_time tm; int ret; - unsigned char data[25]; + unsigned char data[7]; - ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL1, data, + ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_TS_CTRL, data, sizeof(data)); if (ret) { dev_err(dev, "%s: read error ret=%d\n", __func__, ret); @@ -450,20 +444,16 @@ static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts) } dev_dbg(dev, - "%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, ts_sc=%02x, ts_mn=%02x, ts_hr=%02x, ts_dm=%02x, ts_mo=%02x, ts_yr=%02x\n", - __func__, data[PCF2127_REG_CTRL1], data[PCF2127_REG_CTRL2], - data[PCF2127_REG_CTRL3], data[PCF2127_REG_TS_SC], - data[PCF2127_REG_TS_MN], data[PCF2127_REG_TS_HR], - data[PCF2127_REG_TS_DM], data[PCF2127_REG_TS_MO], - data[PCF2127_REG_TS_YR]); - - tm.tm_sec = bcd2bin(data[PCF2127_REG_TS_SC] & 0x7F); - tm.tm_min = bcd2bin(data[PCF2127_REG_TS_MN] & 0x7F); - tm.tm_hour = bcd2bin(data[PCF2127_REG_TS_HR] & 0x3F); - tm.tm_mday = bcd2bin(data[PCF2127_REG_TS_DM] & 0x3F); + "%s: raw data is ts_sc=%02x, ts_mn=%02x, ts_hr=%02x, ts_dm=%02x, ts_mo=%02x, ts_yr=%02x\n", + __func__, data[1], data[2], data[3], data[4], data[5], data[6]); + + tm.tm_sec = bcd2bin(data[1] & 0x7F); + tm.tm_min = bcd2bin(data[2] & 0x7F); + tm.tm_hour = bcd2bin(data[3] & 0x3F); + tm.tm_mday = bcd2bin(data[4] & 0x3F); /* TS_MO register (month) value range: 1-12 */ - tm.tm_mon = bcd2bin(data[PCF2127_REG_TS_MO] & 0x1F) - 1; - tm.tm_year = bcd2bin(data[PCF2127_REG_TS_YR]); + tm.tm_mon = bcd2bin(data[5] & 0x1F) - 1; + tm.tm_year = bcd2bin(data[6]); if (tm.tm_year < 70) tm.tm_year += 100; /* assume we are in 1970...2069 */ -- GitLab From 3d740c647ff8b77b2a560ebd95ac746c46f49ed4 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:46 -0400 Subject: [PATCH 0442/3445] rtc: pcf2127: lower message severity if setting time fails Noted while reviewing new PCF2131 driver. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-4-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 3332d26aee118..2a4d980bb7d5a 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -181,8 +181,7 @@ static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm) /* write register's data */ err = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_SC, buf, i); if (err) { - dev_err(dev, - "%s: err=%d", __func__, err); + dev_dbg(dev, "%s: err=%d", __func__, err); return err; } -- GitLab From 0476b6c8e8b1a6dfa3a259bc7e3c135145532c71 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:47 -0400 Subject: [PATCH 0443/3445] rtc: pcf2127: remove superfluous comments Noted while reviewing new PCF2131 driver. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-5-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 2a4d980bb7d5a..309d1710a1c85 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -137,10 +137,10 @@ static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_sec = bcd2bin(buf[0] & 0x7F); tm->tm_min = bcd2bin(buf[1] & 0x7F); - tm->tm_hour = bcd2bin(buf[2] & 0x3F); /* rtc hr 0-23 */ + tm->tm_hour = bcd2bin(buf[2] & 0x3F); tm->tm_mday = bcd2bin(buf[3] & 0x3F); tm->tm_wday = buf[4] & 0x07; - tm->tm_mon = bcd2bin(buf[5] & 0x1F) - 1; /* rtc mn 1-12 */ + tm->tm_mon = bcd2bin(buf[5] & 0x1F) - 1; tm->tm_year = bcd2bin(buf[6]); tm->tm_year += 100; -- GitLab From fd28ceb4603f9541dcb4ed12b1365cff5af38203 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:48 -0400 Subject: [PATCH 0444/3445] rtc: pcf2127: add variant-specific configuration structure Create variant-specific configuration structures to simplify the implementation of new variants into this driver. It will also avoid to have too many tests for a specific variant, or a list of variants for new devices, inside the code itself. Add configuration options for the support of the NVMEM, bit CD0 in register WD_CTL as well as the maximum number of registers for each variant, instead of hardcoding the variant (PCF2127) inside the i2c_device_id and spi_device_id structures. Also specify a different maximum number of registers (max_register) for the PCF2129. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-6-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 98 +++++++++++++++++++++++++++++++-------- 1 file changed, 79 insertions(+), 19 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 309d1710a1c85..23ab872c36cb2 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -89,10 +90,24 @@ PCF2127_BIT_CTRL2_WDTF | \ PCF2127_BIT_CTRL2_TSF2) +enum pcf21xx_type { + PCF2127, + PCF2129, + PCF21XX_LAST_ID +}; + +struct pcf21xx_config { + int type; /* IC variant */ + int max_register; + unsigned int has_nvmem:1; + unsigned int has_bit_wd_ctl_cd0:1; +}; + struct pcf2127 { struct rtc_device *rtc; struct watchdog_device wdd; struct regmap *regmap; + const struct pcf21xx_config *cfg; time64_t ts; bool ts_valid; bool irq_enabled; @@ -606,8 +621,23 @@ static const struct attribute_group pcf2127_attr_group = { .attrs = pcf2127_attrs, }; +static struct pcf21xx_config pcf21xx_cfg[] = { + [PCF2127] = { + .type = PCF2127, + .max_register = 0x1d, + .has_nvmem = 1, + .has_bit_wd_ctl_cd0 = 1, + }, + [PCF2129] = { + .type = PCF2129, + .max_register = 0x19, + .has_nvmem = 0, + .has_bit_wd_ctl_cd0 = 0, + }, +}; + static int pcf2127_probe(struct device *dev, struct regmap *regmap, - int alarm_irq, const char *name, bool is_pcf2127) + int alarm_irq, const char *name, const struct pcf21xx_config *config) { struct pcf2127 *pcf2127; int ret = 0; @@ -620,6 +650,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, return -ENOMEM; pcf2127->regmap = regmap; + pcf2127->cfg = config; dev_set_drvdata(dev, pcf2127); @@ -663,7 +694,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, set_bit(RTC_FEATURE_ALARM, pcf2127->rtc->features); } - if (is_pcf2127) { + if (pcf2127->cfg->has_nvmem) { struct nvmem_config nvmem_cfg = { .priv = pcf2127, .reg_read = pcf2127_nvmem_read, @@ -709,7 +740,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, PCF2127_BIT_WD_CTL_TF1 | PCF2127_BIT_WD_CTL_TF0, PCF2127_BIT_WD_CTL_CD1 | - (is_pcf2127 ? PCF2127_BIT_WD_CTL_CD0 : 0) | + (pcf2127->cfg->has_bit_wd_ctl_cd0 ? PCF2127_BIT_WD_CTL_CD0 : 0) | PCF2127_BIT_WD_CTL_TF1); if (ret) { dev_err(dev, "%s: watchdog config (wd_ctl) failed\n", __func__); @@ -774,9 +805,9 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, #ifdef CONFIG_OF static const struct of_device_id pcf2127_of_match[] = { - { .compatible = "nxp,pcf2127" }, - { .compatible = "nxp,pcf2129" }, - { .compatible = "nxp,pca2129" }, + { .compatible = "nxp,pcf2127", .data = &pcf21xx_cfg[PCF2127] }, + { .compatible = "nxp,pcf2129", .data = &pcf21xx_cfg[PCF2129] }, + { .compatible = "nxp,pca2129", .data = &pcf21xx_cfg[PCF2129] }, {} }; MODULE_DEVICE_TABLE(of, pcf2127_of_match); @@ -861,26 +892,40 @@ static const struct regmap_bus pcf2127_i2c_regmap = { static struct i2c_driver pcf2127_i2c_driver; static const struct i2c_device_id pcf2127_i2c_id[] = { - { "pcf2127", 1 }, - { "pcf2129", 0 }, - { "pca2129", 0 }, + { "pcf2127", PCF2127 }, + { "pcf2129", PCF2129 }, + { "pca2129", PCF2129 }, { } }; MODULE_DEVICE_TABLE(i2c, pcf2127_i2c_id); static int pcf2127_i2c_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_match_id(pcf2127_i2c_id, client); struct regmap *regmap; - static const struct regmap_config config = { + static struct regmap_config config = { .reg_bits = 8, .val_bits = 8, - .max_register = 0x1d, }; + const struct pcf21xx_config *variant; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; + if (client->dev.of_node) { + variant = of_device_get_match_data(&client->dev); + if (!variant) + return -ENODEV; + } else { + enum pcf21xx_type type = + i2c_match_id(pcf2127_i2c_id, client)->driver_data; + + if (type >= PCF21XX_LAST_ID) + return -ENODEV; + variant = &pcf21xx_cfg[type]; + } + + config.max_register = variant->max_register, + regmap = devm_regmap_init(&client->dev, &pcf2127_i2c_regmap, &client->dev, &config); if (IS_ERR(regmap)) { @@ -890,7 +935,7 @@ static int pcf2127_i2c_probe(struct i2c_client *client) } return pcf2127_probe(&client->dev, regmap, client->irq, - pcf2127_i2c_driver.driver.name, id->driver_data); + pcf2127_i2c_driver.driver.name, variant); } static struct i2c_driver pcf2127_i2c_driver = { @@ -928,17 +973,32 @@ static void pcf2127_i2c_unregister_driver(void) #if IS_ENABLED(CONFIG_SPI_MASTER) static struct spi_driver pcf2127_spi_driver; +static const struct spi_device_id pcf2127_spi_id[]; static int pcf2127_spi_probe(struct spi_device *spi) { - static const struct regmap_config config = { + static struct regmap_config config = { .reg_bits = 8, .val_bits = 8, .read_flag_mask = 0xa0, .write_flag_mask = 0x20, - .max_register = 0x1d, }; struct regmap *regmap; + const struct pcf21xx_config *variant; + + if (spi->dev.of_node) { + variant = of_device_get_match_data(&spi->dev); + if (!variant) + return -ENODEV; + } else { + enum pcf21xx_type type = spi_get_device_id(spi)->driver_data; + + if (type >= PCF21XX_LAST_ID) + return -ENODEV; + variant = &pcf21xx_cfg[type]; + } + + config.max_register = variant->max_register, regmap = devm_regmap_init_spi(spi, &config); if (IS_ERR(regmap)) { @@ -949,13 +1009,13 @@ static int pcf2127_spi_probe(struct spi_device *spi) return pcf2127_probe(&spi->dev, regmap, spi->irq, pcf2127_spi_driver.driver.name, - spi_get_device_id(spi)->driver_data); + variant); } static const struct spi_device_id pcf2127_spi_id[] = { - { "pcf2127", 1 }, - { "pcf2129", 0 }, - { "pca2129", 0 }, + { "pcf2127", PCF2127 }, + { "pcf2129", PCF2129 }, + { "pca2129", PCF2129 }, { } }; MODULE_DEVICE_TABLE(spi, pcf2127_spi_id); -- GitLab From 6211acee8edf4af61f7745a92c4b4cb05a4340f9 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:49 -0400 Subject: [PATCH 0445/3445] rtc: pcf2127: adapt for time/date registers at any offset This will simplify the implementation of new variants into this driver. Some variants (PCF2131) have a 100th seconds register. This register is currently not supported in this driver. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-7-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 23ab872c36cb2..e65e86e08acc3 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -44,7 +44,7 @@ #define PCF2127_BIT_CTRL3_BF BIT(3) #define PCF2127_BIT_CTRL3_BTSE BIT(4) /* Time and date registers */ -#define PCF2127_REG_SC 0x03 +#define PCF2127_REG_TIME_BASE 0x03 #define PCF2127_BIT_SC_OSF BIT(7) /* Alarm registers */ #define PCF2127_REG_ALARM_SC 0x0A @@ -101,6 +101,7 @@ struct pcf21xx_config { int max_register; unsigned int has_nvmem:1; unsigned int has_bit_wd_ctl_cd0:1; + u8 reg_time_base; /* Time/date base register. */ }; struct pcf2127 { @@ -127,8 +128,8 @@ static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) * Avoid reading CTRL2 register as it causes WD_VAL register * value to reset to 0 which means watchdog is stopped. */ - ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_SC, buf, - sizeof(buf)); + ret = regmap_bulk_read(pcf2127->regmap, pcf2127->cfg->reg_time_base, + buf, sizeof(buf)); if (ret) { dev_err(dev, "%s: read error\n", __func__); return ret; @@ -194,7 +195,7 @@ static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm) buf[i++] = bin2bcd(tm->tm_year - 100); /* write register's data */ - err = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_SC, buf, i); + err = regmap_bulk_write(pcf2127->regmap, pcf2127->cfg->reg_time_base, buf, i); if (err) { dev_dbg(dev, "%s: err=%d", __func__, err); return err; @@ -627,12 +628,14 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .max_register = 0x1d, .has_nvmem = 1, .has_bit_wd_ctl_cd0 = 1, + .reg_time_base = PCF2127_REG_TIME_BASE, }, [PCF2129] = { .type = PCF2129, .max_register = 0x19, .has_nvmem = 0, .has_bit_wd_ctl_cd0 = 0, + .reg_time_base = PCF2127_REG_TIME_BASE, }, }; -- GitLab From 7c6f0db41ab5fbd7ee3a2f9880ac23509a5d55d1 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:50 -0400 Subject: [PATCH 0446/3445] rtc: pcf2127: adapt for alarm registers at any offset This will simplify the implementation of new variants into this driver. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-8-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index e65e86e08acc3..8849d57c0384a 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -47,11 +47,7 @@ #define PCF2127_REG_TIME_BASE 0x03 #define PCF2127_BIT_SC_OSF BIT(7) /* Alarm registers */ -#define PCF2127_REG_ALARM_SC 0x0A -#define PCF2127_REG_ALARM_MN 0x0B -#define PCF2127_REG_ALARM_HR 0x0C -#define PCF2127_REG_ALARM_DM 0x0D -#define PCF2127_REG_ALARM_DW 0x0E +#define PCF2127_REG_ALARM_BASE 0x0A #define PCF2127_BIT_ALARM_AE BIT(7) /* CLKOUT control register */ #define PCF2127_REG_CLKOUT 0x0f @@ -102,6 +98,7 @@ struct pcf21xx_config { unsigned int has_nvmem:1; unsigned int has_bit_wd_ctl_cd0:1; u8 reg_time_base; /* Time/date base register. */ + u8 regs_alarm_base; /* Alarm function base registers. */ }; struct pcf2127 { @@ -381,8 +378,8 @@ static int pcf2127_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) if (ret) return ret; - ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_ALARM_SC, buf, - sizeof(buf)); + ret = regmap_bulk_read(pcf2127->regmap, pcf2127->cfg->regs_alarm_base, + buf, sizeof(buf)); if (ret) return ret; @@ -432,8 +429,8 @@ static int pcf2127_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) buf[3] = bin2bcd(alrm->time.tm_mday); buf[4] = PCF2127_BIT_ALARM_AE; /* Do not match on week day */ - ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_ALARM_SC, buf, - sizeof(buf)); + ret = regmap_bulk_write(pcf2127->regmap, pcf2127->cfg->regs_alarm_base, + buf, sizeof(buf)); if (ret) return ret; @@ -629,6 +626,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .has_nvmem = 1, .has_bit_wd_ctl_cd0 = 1, .reg_time_base = PCF2127_REG_TIME_BASE, + .regs_alarm_base = PCF2127_REG_ALARM_BASE, }, [PCF2129] = { .type = PCF2129, @@ -636,6 +634,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .has_nvmem = 0, .has_bit_wd_ctl_cd0 = 0, .reg_time_base = PCF2127_REG_TIME_BASE, + .regs_alarm_base = PCF2127_REG_ALARM_BASE, }, }; -- GitLab From 6b57ec29e3fc31d43e672f6fede5d4a76140308b Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:51 -0400 Subject: [PATCH 0447/3445] rtc: pcf2127: adapt for WD registers at any offset This will simplify the implementation of new variants into this driver. Signed-off-by: Hugo Villeneuve Reviewed-by: Bruno Thomsen Tested-by: Bruno Thomsen Link: https://lore.kernel.org/r/20230622145800.2442116-9-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 8849d57c0384a..fb1b2b89e9098 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -99,6 +99,8 @@ struct pcf21xx_config { unsigned int has_bit_wd_ctl_cd0:1; u8 reg_time_base; /* Time/date base register. */ u8 regs_alarm_base; /* Alarm function base registers. */ + u8 reg_wd_ctl; /* Watchdog control register. */ + u8 reg_wd_val; /* Watchdog value register. */ }; struct pcf2127 { @@ -269,7 +271,7 @@ static int pcf2127_wdt_ping(struct watchdog_device *wdd) { struct pcf2127 *pcf2127 = watchdog_get_drvdata(wdd); - return regmap_write(pcf2127->regmap, PCF2127_REG_WD_VAL, wdd->timeout); + return regmap_write(pcf2127->regmap, pcf2127->cfg->reg_wd_val, wdd->timeout); } /* @@ -303,7 +305,7 @@ static int pcf2127_wdt_stop(struct watchdog_device *wdd) { struct pcf2127 *pcf2127 = watchdog_get_drvdata(wdd); - return regmap_write(pcf2127->regmap, PCF2127_REG_WD_VAL, + return regmap_write(pcf2127->regmap, pcf2127->cfg->reg_wd_val, PCF2127_WD_VAL_STOP); } @@ -352,7 +354,7 @@ static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127) watchdog_set_drvdata(&pcf2127->wdd, pcf2127); /* Test if watchdog timer is started by bootloader */ - ret = regmap_read(pcf2127->regmap, PCF2127_REG_WD_VAL, &wdd_timeout); + ret = regmap_read(pcf2127->regmap, pcf2127->cfg->reg_wd_val, &wdd_timeout); if (ret) return ret; @@ -627,6 +629,8 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .has_bit_wd_ctl_cd0 = 1, .reg_time_base = PCF2127_REG_TIME_BASE, .regs_alarm_base = PCF2127_REG_ALARM_BASE, + .reg_wd_ctl = PCF2127_REG_WD_CTL, + .reg_wd_val = PCF2127_REG_WD_VAL, }, [PCF2129] = { .type = PCF2129, @@ -635,6 +639,8 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .has_bit_wd_ctl_cd0 = 0, .reg_time_base = PCF2127_REG_TIME_BASE, .regs_alarm_base = PCF2127_REG_ALARM_BASE, + .reg_wd_ctl = PCF2127_REG_WD_CTL, + .reg_wd_val = PCF2127_REG_WD_VAL, }, }; @@ -736,7 +742,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, * as T. Bits labeled as T must always be written with * logic 0. */ - ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_WD_CTL, + ret = regmap_update_bits(pcf2127->regmap, pcf2127->cfg->reg_wd_ctl, PCF2127_BIT_WD_CTL_CD1 | PCF2127_BIT_WD_CTL_CD0 | PCF2127_BIT_WD_CTL_TF1 | -- GitLab From fc16599e0153e91ba12d856e40f6fc56906077f1 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:52 -0400 Subject: [PATCH 0448/3445] rtc: pcf2127: adapt for CLKOUT register at any offset This will simplify the implementation of new variants into this driver. Signed-off-by: Hugo Villeneuve Reviewed-by: Bruno Thomsen Link: https://lore.kernel.org/r/20230622145800.2442116-10-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index fb1b2b89e9098..c4c0bf574e6b0 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -101,6 +101,7 @@ struct pcf21xx_config { u8 regs_alarm_base; /* Alarm function base registers. */ u8 reg_wd_ctl; /* Watchdog control register. */ u8 reg_wd_val; /* Watchdog value register. */ + u8 reg_clkout; /* Clkout register. */ }; struct pcf2127 { @@ -631,6 +632,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .regs_alarm_base = PCF2127_REG_ALARM_BASE, .reg_wd_ctl = PCF2127_REG_WD_CTL, .reg_wd_val = PCF2127_REG_WD_VAL, + .reg_clkout = PCF2127_REG_CLKOUT, }, [PCF2129] = { .type = PCF2129, @@ -641,6 +643,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .regs_alarm_base = PCF2127_REG_ALARM_BASE, .reg_wd_ctl = PCF2127_REG_WD_CTL, .reg_wd_val = PCF2127_REG_WD_VAL, + .reg_clkout = PCF2127_REG_CLKOUT, }, }; @@ -720,12 +723,12 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, regmap_clear_bits(pcf2127->regmap, PCF2127_REG_CTRL1, PCF2127_BIT_CTRL1_POR_OVRD); - ret = regmap_read(pcf2127->regmap, PCF2127_REG_CLKOUT, &val); + ret = regmap_read(pcf2127->regmap, pcf2127->cfg->reg_clkout, &val); if (ret < 0) return ret; if (!(val & PCF2127_BIT_CLKOUT_OTPR)) { - ret = regmap_set_bits(pcf2127->regmap, PCF2127_REG_CLKOUT, + ret = regmap_set_bits(pcf2127->regmap, pcf2127->cfg->reg_clkout, PCF2127_BIT_CLKOUT_OTPR); if (ret < 0) return ret; -- GitLab From 420cc9e850dbc8e6ea7dd1e53d62d64cd8766354 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:53 -0400 Subject: [PATCH 0449/3445] rtc: pcf2127: add support for multiple TS functions This will simplify the implementation of new variants into this driver. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-11-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 268 ++++++++++++++++++++++++++++---------- 1 file changed, 201 insertions(+), 67 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index c4c0bf574e6b0..9d91cff173cf2 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -59,8 +59,8 @@ #define PCF2127_BIT_WD_CTL_CD0 BIT(6) #define PCF2127_BIT_WD_CTL_CD1 BIT(7) #define PCF2127_REG_WD_VAL 0x11 -/* Tamper timestamp registers */ -#define PCF2127_REG_TS_CTRL 0x12 +/* Tamper timestamp1 registers */ +#define PCF2127_REG_TS1_BASE 0x12 #define PCF2127_BIT_TS_CTRL_TSOFF BIT(6) #define PCF2127_BIT_TS_CTRL_TSM BIT(7) /* @@ -86,12 +86,36 @@ PCF2127_BIT_CTRL2_WDTF | \ PCF2127_BIT_CTRL2_TSF2) +#define PCF2127_MAX_TS_SUPPORTED 1 + enum pcf21xx_type { PCF2127, PCF2129, PCF21XX_LAST_ID }; +struct pcf21xx_ts_config { + u8 reg_base; /* Base register to read timestamp values. */ + + /* + * If the TS input pin is driven to GND, an interrupt can be generated + * (supported by all variants). + */ + u8 gnd_detect_reg; /* Interrupt control register address. */ + u8 gnd_detect_bit; /* Interrupt bit. */ + + /* + * If the TS input pin is driven to an intermediate level between GND + * and supply, an interrupt can be generated (optional feature depending + * on variant). + */ + u8 inter_detect_reg; /* Interrupt control register address. */ + u8 inter_detect_bit; /* Interrupt bit. */ + + u8 ie_reg; /* Interrupt enable control register. */ + u8 ie_bit; /* Interrupt enable bit. */ +}; + struct pcf21xx_config { int type; /* IC variant */ int max_register; @@ -102,6 +126,9 @@ struct pcf21xx_config { u8 reg_wd_ctl; /* Watchdog control register. */ u8 reg_wd_val; /* Watchdog value register. */ u8 reg_clkout; /* Clkout register. */ + unsigned int ts_count; + struct pcf21xx_ts_config ts[PCF2127_MAX_TS_SUPPORTED]; + struct attribute_group attribute_group; }; struct pcf2127 { @@ -109,9 +136,9 @@ struct pcf2127 { struct watchdog_device wdd; struct regmap *regmap; const struct pcf21xx_config *cfg; - time64_t ts; - bool ts_valid; bool irq_enabled; + time64_t ts[PCF2127_MAX_TS_SUPPORTED]; /* Timestamp values. */ + bool ts_valid[PCF2127_MAX_TS_SUPPORTED]; /* Timestamp valid indication. */ }; /* @@ -441,18 +468,19 @@ static int pcf2127_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) } /* - * This function reads ctrl2 register, caller is responsible for calling - * pcf2127_wdt_active_ping() + * This function reads one timestamp function data, caller is responsible for + * calling pcf2127_wdt_active_ping() */ -static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts) +static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts, + int ts_id) { struct pcf2127 *pcf2127 = dev_get_drvdata(dev); struct rtc_time tm; int ret; unsigned char data[7]; - ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_TS_CTRL, data, - sizeof(data)); + ret = regmap_bulk_read(pcf2127->regmap, pcf2127->cfg->ts[ts_id].reg_base, + data, sizeof(data)); if (ret) { dev_err(dev, "%s: read error ret=%d\n", __func__, ret); return ret; @@ -482,18 +510,21 @@ static int pcf2127_rtc_ts_read(struct device *dev, time64_t *ts) return 0; }; -static void pcf2127_rtc_ts_snapshot(struct device *dev) +static void pcf2127_rtc_ts_snapshot(struct device *dev, int ts_id) { struct pcf2127 *pcf2127 = dev_get_drvdata(dev); int ret; + if (ts_id >= pcf2127->cfg->ts_count) + return; + /* Let userspace read the first timestamp */ - if (pcf2127->ts_valid) + if (pcf2127->ts_valid[ts_id]) return; - ret = pcf2127_rtc_ts_read(dev, &pcf2127->ts); + ret = pcf2127_rtc_ts_read(dev, &pcf2127->ts[ts_id], ts_id); if (!ret) - pcf2127->ts_valid = true; + pcf2127->ts_valid[ts_id] = true; } static irqreturn_t pcf2127_rtc_irq(int irq, void *dev) @@ -514,7 +545,7 @@ static irqreturn_t pcf2127_rtc_irq(int irq, void *dev) return IRQ_NONE; if (ctrl1 & PCF2127_BIT_CTRL1_TSF1 || ctrl2 & PCF2127_BIT_CTRL2_TSF2) - pcf2127_rtc_ts_snapshot(dev); + pcf2127_rtc_ts_snapshot(dev, 0); if (ctrl1 & PCF2127_CTRL1_IRQ_MASK) regmap_write(pcf2127->regmap, PCF2127_REG_CTRL1, @@ -543,28 +574,41 @@ static const struct rtc_class_ops pcf2127_rtc_ops = { /* sysfs interface */ -static ssize_t timestamp0_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t timestamp_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count, int ts_id) { struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent); int ret; + if (ts_id >= pcf2127->cfg->ts_count) + return 0; + if (pcf2127->irq_enabled) { - pcf2127->ts_valid = false; + pcf2127->ts_valid[ts_id] = false; } else { - ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1, - PCF2127_BIT_CTRL1_TSF1, 0); + /* Always clear GND interrupt bit. */ + ret = regmap_update_bits(pcf2127->regmap, + pcf2127->cfg->ts[ts_id].gnd_detect_reg, + pcf2127->cfg->ts[ts_id].gnd_detect_bit, + 0); + if (ret) { - dev_err(dev, "%s: update ctrl1 ret=%d\n", __func__, ret); + dev_err(dev, "%s: update TS gnd detect ret=%d\n", __func__, ret); return ret; } - ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2, - PCF2127_BIT_CTRL2_TSF2, 0); - if (ret) { - dev_err(dev, "%s: update ctrl2 ret=%d\n", __func__, ret); - return ret; + if (pcf2127->cfg->ts[ts_id].inter_detect_bit) { + /* Clear intermediate level interrupt bit if supported. */ + ret = regmap_update_bits(pcf2127->regmap, + pcf2127->cfg->ts[ts_id].inter_detect_reg, + pcf2127->cfg->ts[ts_id].inter_detect_bit, + 0); + if (ret) { + dev_err(dev, "%s: update TS intermediate level detect ret=%d\n", + __func__, ret); + return ret; + } } ret = pcf2127_wdt_active_ping(&pcf2127->wdd); @@ -573,34 +617,63 @@ static ssize_t timestamp0_store(struct device *dev, } return count; +} + +static ssize_t timestamp0_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return timestamp_store(dev, attr, buf, count, 0); }; -static ssize_t timestamp0_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t timestamp_show(struct device *dev, + struct device_attribute *attr, char *buf, + int ts_id) { struct pcf2127 *pcf2127 = dev_get_drvdata(dev->parent); - unsigned int ctrl1, ctrl2; int ret; time64_t ts; + if (ts_id >= pcf2127->cfg->ts_count) + return 0; + if (pcf2127->irq_enabled) { - if (!pcf2127->ts_valid) + if (!pcf2127->ts_valid[ts_id]) return 0; - ts = pcf2127->ts; + ts = pcf2127->ts[ts_id]; } else { - ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1, &ctrl1); - if (ret) - return 0; + u8 valid_low = 0; + u8 valid_inter = 0; + unsigned int ctrl; - ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL2, &ctrl2); + /* Check if TS input pin is driven to GND, supported by all + * variants. + */ + ret = regmap_read(pcf2127->regmap, + pcf2127->cfg->ts[ts_id].gnd_detect_reg, + &ctrl); if (ret) return 0; - if (!(ctrl1 & PCF2127_BIT_CTRL1_TSF1) && - !(ctrl2 & PCF2127_BIT_CTRL2_TSF2)) + valid_low = ctrl & pcf2127->cfg->ts[ts_id].gnd_detect_bit; + + if (pcf2127->cfg->ts[ts_id].inter_detect_bit) { + /* Check if TS input pin is driven to intermediate level + * between GND and supply, if supported by variant. + */ + ret = regmap_read(pcf2127->regmap, + pcf2127->cfg->ts[ts_id].inter_detect_reg, + &ctrl); + if (ret) + return 0; + + valid_inter = ctrl & pcf2127->cfg->ts[ts_id].inter_detect_bit; + } + + if (!valid_low && !valid_inter) return 0; - ret = pcf2127_rtc_ts_read(dev->parent, &ts); + ret = pcf2127_rtc_ts_read(dev->parent, &ts, ts_id); if (ret) return 0; @@ -609,6 +682,12 @@ static ssize_t timestamp0_show(struct device *dev, return ret; } return sprintf(buf, "%llu\n", (unsigned long long)ts); +} + +static ssize_t timestamp0_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return timestamp_show(dev, attr, buf, 0); }; static DEVICE_ATTR_RW(timestamp0); @@ -618,10 +697,6 @@ static struct attribute *pcf2127_attrs[] = { NULL }; -static const struct attribute_group pcf2127_attr_group = { - .attrs = pcf2127_attrs, -}; - static struct pcf21xx_config pcf21xx_cfg[] = { [PCF2127] = { .type = PCF2127, @@ -633,6 +708,19 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .reg_wd_ctl = PCF2127_REG_WD_CTL, .reg_wd_val = PCF2127_REG_WD_VAL, .reg_clkout = PCF2127_REG_CLKOUT, + .ts_count = 1, + .ts[0] = { + .reg_base = PCF2127_REG_TS1_BASE, + .gnd_detect_reg = PCF2127_REG_CTRL1, + .gnd_detect_bit = PCF2127_BIT_CTRL1_TSF1, + .inter_detect_reg = PCF2127_REG_CTRL2, + .inter_detect_bit = PCF2127_BIT_CTRL2_TSF2, + .ie_reg = PCF2127_REG_CTRL2, + .ie_bit = PCF2127_BIT_CTRL2_TSIE, + }, + .attribute_group = { + .attrs = pcf2127_attrs, + }, }, [PCF2129] = { .type = PCF2129, @@ -644,9 +732,74 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .reg_wd_ctl = PCF2127_REG_WD_CTL, .reg_wd_val = PCF2127_REG_WD_VAL, .reg_clkout = PCF2127_REG_CLKOUT, + .ts_count = 1, + .ts[0] = { + .reg_base = PCF2127_REG_TS1_BASE, + .gnd_detect_reg = PCF2127_REG_CTRL1, + .gnd_detect_bit = PCF2127_BIT_CTRL1_TSF1, + .inter_detect_reg = PCF2127_REG_CTRL2, + .inter_detect_bit = PCF2127_BIT_CTRL2_TSF2, + .ie_reg = PCF2127_REG_CTRL2, + .ie_bit = PCF2127_BIT_CTRL2_TSIE, + }, + .attribute_group = { + .attrs = pcf2127_attrs, + }, }, }; +/* + * Enable timestamp function and corresponding interrupt(s). + */ +static int pcf2127_enable_ts(struct device *dev, int ts_id) +{ + struct pcf2127 *pcf2127 = dev_get_drvdata(dev); + int ret; + + if (ts_id >= pcf2127->cfg->ts_count) { + dev_err(dev, "%s: invalid tamper detection ID (%d)\n", + __func__, ts_id); + return -EINVAL; + } + + /* Enable timestamp function. */ + ret = regmap_update_bits(pcf2127->regmap, + pcf2127->cfg->ts[ts_id].reg_base, + PCF2127_BIT_TS_CTRL_TSOFF | + PCF2127_BIT_TS_CTRL_TSM, + PCF2127_BIT_TS_CTRL_TSM); + if (ret) { + dev_err(dev, "%s: tamper detection config (ts%d_ctrl) failed\n", + __func__, ts_id); + return ret; + } + + /* TS input pin driven to GND detection is supported by all variants. + * Make sure that interrupt bit is defined. + */ + if (pcf2127->cfg->ts[ts_id].gnd_detect_bit == 0) { + dev_err(dev, "%s: tamper detection to GND configuration invalid\n", + __func__); + return ret; + } + + /* + * Enable interrupt generation when TSF timestamp flag is set. + * Interrupt signals are open-drain outputs and can be left floating if + * unused. + */ + ret = regmap_update_bits(pcf2127->regmap, pcf2127->cfg->ts[ts_id].ie_reg, + pcf2127->cfg->ts[ts_id].ie_bit, + pcf2127->cfg->ts[ts_id].ie_bit); + if (ret) { + dev_err(dev, "%s: tamper detection TSIE%d config failed\n", + __func__, ts_id); + return ret; + } + + return ret; +} + static int pcf2127_probe(struct device *dev, struct regmap *regmap, int alarm_irq, const char *name, const struct pcf21xx_config *config) { @@ -777,34 +930,15 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, } /* - * Enable timestamp function and store timestamp of first trigger - * event until TSF1 and TSF2 interrupt flags are cleared. + * Enable timestamp functions 1 to 4. */ - ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_TS_CTRL, - PCF2127_BIT_TS_CTRL_TSOFF | - PCF2127_BIT_TS_CTRL_TSM, - PCF2127_BIT_TS_CTRL_TSM); - if (ret) { - dev_err(dev, "%s: tamper detection config (ts_ctrl) failed\n", - __func__); - return ret; - } - - /* - * Enable interrupt generation when TSF1 or TSF2 timestamp flags - * are set. Interrupt signal is an open-drain output and can be - * left floating if unused. - */ - ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL2, - PCF2127_BIT_CTRL2_TSIE, - PCF2127_BIT_CTRL2_TSIE); - if (ret) { - dev_err(dev, "%s: tamper detection config (ctrl2) failed\n", - __func__); - return ret; + for (int i = 0; i < pcf2127->cfg->ts_count; i++) { + ret = pcf2127_enable_ts(dev, i); + if (ret) + return ret; } - ret = rtc_add_group(pcf2127->rtc, &pcf2127_attr_group); + ret = rtc_add_group(pcf2127->rtc, &pcf2127->cfg->attribute_group); if (ret) { dev_err(dev, "%s: tamper sysfs registering failed\n", __func__); -- GitLab From afc505bf9039caf5a377d8b9705ef42f6d4ac7d4 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:54 -0400 Subject: [PATCH 0450/3445] rtc: pcf2127: add support for PCF2131 RTC This RTC is very similar in functionality to the PCF2127/29. Basically it: -supports two new control registers at offsets 4 and 5 -supports a new reset register (not implemented in this driver) -supports 4 tamper detection functions instead of 1 -has no nvmem (like the PCF2129) -has two output interrupt pins Because of that, most of the register addresses are very different, although they still follow the same layout. For example, the tamper registers have a different base address, but the offsets are all the same. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-12-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 4 +- drivers/rtc/rtc-pcf2127.c | 234 ++++++++++++++++++++++++++++++++++---- 2 files changed, 215 insertions(+), 23 deletions(-) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 05f4b2d66290d..e8bad8c93ba99 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -904,9 +904,9 @@ config RTC_DRV_PCF2127 select REGMAP_SPI if SPI_MASTER select WATCHDOG_CORE if WATCHDOG help - If you say yes here you get support for the NXP PCF2127/29 RTC + If you say yes here you get support for the NXP PCF2127/29/31 RTC chips with integrated quartz crystal for industrial applications. - Both chips also have watchdog timer and tamper switch detection + These chips also have watchdog timer and tamper switch detection features. PCF2127 has an additional feature of 512 bytes battery backed diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 9d91cff173cf2..8c2ad9eac861b 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * An I2C and SPI driver for the NXP PCF2127/29 RTC + * An I2C and SPI driver for the NXP PCF2127/29/31 RTC * Copyright 2013 Til-Technologies * * Author: Renaud Cerrato @@ -8,9 +8,13 @@ * Watchdog and tamper functions * Author: Bruno Thomsen * + * PCF2131 support + * Author: Hugo Villeneuve + * * based on the other drivers in this same directory. * - * Datasheet: https://www.nxp.com/docs/en/data-sheet/PCF2127.pdf + * Datasheets: https://www.nxp.com/docs/en/data-sheet/PCF2127.pdf + * https://www.nxp.com/docs/en/data-sheet/PCF2131DS.pdf */ #include @@ -67,7 +71,7 @@ * RAM registers * PCF2127 has 512 bytes general-purpose static RAM (SRAM) that is * battery backed and can survive a power outage. - * PCF2129 doesn't have this feature. + * PCF2129/31 doesn't have this feature. */ #define PCF2127_REG_RAM_ADDR_MSB 0x1A #define PCF2127_REG_RAM_WRT_CMD 0x1C @@ -86,11 +90,65 @@ PCF2127_BIT_CTRL2_WDTF | \ PCF2127_BIT_CTRL2_TSF2) -#define PCF2127_MAX_TS_SUPPORTED 1 +#define PCF2127_MAX_TS_SUPPORTED 4 + +/* Control register 4 */ +#define PCF2131_REG_CTRL4 0x03 +#define PCF2131_BIT_CTRL4_TSF4 BIT(4) +#define PCF2131_BIT_CTRL4_TSF3 BIT(5) +#define PCF2131_BIT_CTRL4_TSF2 BIT(6) +#define PCF2131_BIT_CTRL4_TSF1 BIT(7) +/* Control register 5 */ +#define PCF2131_REG_CTRL5 0x04 +#define PCF2131_BIT_CTRL5_TSIE4 BIT(4) +#define PCF2131_BIT_CTRL5_TSIE3 BIT(5) +#define PCF2131_BIT_CTRL5_TSIE2 BIT(6) +#define PCF2131_BIT_CTRL5_TSIE1 BIT(7) +/* Software reset register */ +#define PCF2131_REG_SR_RESET 0x05 +#define PCF2131_SR_RESET_READ_PATTERN (BIT(2) | BIT(5)) +#define PCF2131_SR_RESET_CPR_CMD (PCF2131_SR_RESET_READ_PATTERN | BIT(7)) +/* Time and date registers */ +#define PCF2131_REG_TIME_BASE 0x07 +/* Alarm registers */ +#define PCF2131_REG_ALARM_BASE 0x0E +/* CLKOUT control register */ +#define PCF2131_REG_CLKOUT 0x13 +/* Watchdog registers */ +#define PCF2131_REG_WD_CTL 0x35 +#define PCF2131_REG_WD_VAL 0x36 +/* Tamper timestamp1 registers */ +#define PCF2131_REG_TS1_BASE 0x14 +/* Tamper timestamp2 registers */ +#define PCF2131_REG_TS2_BASE 0x1B +/* Tamper timestamp3 registers */ +#define PCF2131_REG_TS3_BASE 0x22 +/* Tamper timestamp4 registers */ +#define PCF2131_REG_TS4_BASE 0x29 +/* Interrupt mask registers */ +#define PCF2131_REG_INT_A_MASK1 0x31 +#define PCF2131_REG_INT_A_MASK2 0x32 +#define PCF2131_REG_INT_B_MASK1 0x33 +#define PCF2131_REG_INT_B_MASK2 0x34 +#define PCF2131_BIT_INT_BLIE BIT(0) +#define PCF2131_BIT_INT_BIE BIT(1) +#define PCF2131_BIT_INT_AIE BIT(2) +#define PCF2131_BIT_INT_WD_CD BIT(3) +#define PCF2131_BIT_INT_SI BIT(4) +#define PCF2131_BIT_INT_MI BIT(5) +#define PCF2131_CTRL2_IRQ_MASK ( \ + PCF2127_BIT_CTRL2_AF | \ + PCF2127_BIT_CTRL2_WDTF) +#define PCF2131_CTRL4_IRQ_MASK ( \ + PCF2131_BIT_CTRL4_TSF4 | \ + PCF2131_BIT_CTRL4_TSF3 | \ + PCF2131_BIT_CTRL4_TSF2 | \ + PCF2131_BIT_CTRL4_TSF1) enum pcf21xx_type { PCF2127, PCF2129, + PCF2131, PCF21XX_LAST_ID }; @@ -530,30 +588,64 @@ static void pcf2127_rtc_ts_snapshot(struct device *dev, int ts_id) static irqreturn_t pcf2127_rtc_irq(int irq, void *dev) { struct pcf2127 *pcf2127 = dev_get_drvdata(dev); - unsigned int ctrl1, ctrl2; + unsigned int ctrl2; int ret = 0; - ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1, &ctrl1); - if (ret) - return IRQ_NONE; - ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL2, &ctrl2); if (ret) return IRQ_NONE; - if (!(ctrl1 & PCF2127_CTRL1_IRQ_MASK || ctrl2 & PCF2127_CTRL2_IRQ_MASK)) - return IRQ_NONE; + if (pcf2127->cfg->ts_count == 1) { + /* PCF2127/29 */ + unsigned int ctrl1; + + ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1, &ctrl1); + if (ret) + return IRQ_NONE; + + if (!(ctrl1 & PCF2127_CTRL1_IRQ_MASK || ctrl2 & PCF2127_CTRL2_IRQ_MASK)) + return IRQ_NONE; + + if (ctrl1 & PCF2127_BIT_CTRL1_TSF1 || ctrl2 & PCF2127_BIT_CTRL2_TSF2) + pcf2127_rtc_ts_snapshot(dev, 0); + + if (ctrl1 & PCF2127_CTRL1_IRQ_MASK) + regmap_write(pcf2127->regmap, PCF2127_REG_CTRL1, + ctrl1 & ~PCF2127_CTRL1_IRQ_MASK); - if (ctrl1 & PCF2127_BIT_CTRL1_TSF1 || ctrl2 & PCF2127_BIT_CTRL2_TSF2) - pcf2127_rtc_ts_snapshot(dev, 0); + if (ctrl2 & PCF2127_CTRL2_IRQ_MASK) + regmap_write(pcf2127->regmap, PCF2127_REG_CTRL2, + ctrl2 & ~PCF2127_CTRL2_IRQ_MASK); + } else { + /* PCF2131. */ + unsigned int ctrl4; + + ret = regmap_read(pcf2127->regmap, PCF2131_REG_CTRL4, &ctrl4); + if (ret) + return IRQ_NONE; - if (ctrl1 & PCF2127_CTRL1_IRQ_MASK) - regmap_write(pcf2127->regmap, PCF2127_REG_CTRL1, - ctrl1 & ~PCF2127_CTRL1_IRQ_MASK); + if (!(ctrl4 & PCF2131_CTRL4_IRQ_MASK || ctrl2 & PCF2131_CTRL2_IRQ_MASK)) + return IRQ_NONE; - if (ctrl2 & PCF2127_CTRL2_IRQ_MASK) - regmap_write(pcf2127->regmap, PCF2127_REG_CTRL2, - ctrl2 & ~PCF2127_CTRL2_IRQ_MASK); + if (ctrl4 & PCF2131_CTRL4_IRQ_MASK) { + int i; + int tsf_bit = PCF2131_BIT_CTRL4_TSF1; /* Start at bit 7. */ + + for (i = 0; i < pcf2127->cfg->ts_count; i++) { + if (ctrl4 & tsf_bit) + pcf2127_rtc_ts_snapshot(dev, i); + + tsf_bit = tsf_bit >> 1; + } + + regmap_write(pcf2127->regmap, PCF2131_REG_CTRL4, + ctrl4 & ~PCF2131_CTRL4_IRQ_MASK); + } + + if (ctrl2 & PCF2131_CTRL2_IRQ_MASK) + regmap_write(pcf2127->regmap, PCF2127_REG_CTRL2, + ctrl2 & ~PCF2131_CTRL2_IRQ_MASK); + } if (ctrl2 & PCF2127_BIT_CTRL2_AF) rtc_update_irq(pcf2127->rtc, 1, RTC_IRQF | RTC_AF); @@ -626,6 +718,27 @@ static ssize_t timestamp0_store(struct device *dev, return timestamp_store(dev, attr, buf, count, 0); }; +static ssize_t timestamp1_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return timestamp_store(dev, attr, buf, count, 1); +}; + +static ssize_t timestamp2_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return timestamp_store(dev, attr, buf, count, 2); +}; + +static ssize_t timestamp3_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return timestamp_store(dev, attr, buf, count, 3); +}; + static ssize_t timestamp_show(struct device *dev, struct device_attribute *attr, char *buf, int ts_id) @@ -690,13 +803,42 @@ static ssize_t timestamp0_show(struct device *dev, return timestamp_show(dev, attr, buf, 0); }; +static ssize_t timestamp1_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return timestamp_show(dev, attr, buf, 1); +}; + +static ssize_t timestamp2_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return timestamp_show(dev, attr, buf, 2); +}; + +static ssize_t timestamp3_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return timestamp_show(dev, attr, buf, 3); +}; + static DEVICE_ATTR_RW(timestamp0); +static DEVICE_ATTR_RW(timestamp1); +static DEVICE_ATTR_RW(timestamp2); +static DEVICE_ATTR_RW(timestamp3); static struct attribute *pcf2127_attrs[] = { &dev_attr_timestamp0.attr, NULL }; +static struct attribute *pcf2131_attrs[] = { + &dev_attr_timestamp0.attr, + &dev_attr_timestamp1.attr, + &dev_attr_timestamp2.attr, + &dev_attr_timestamp3.attr, + NULL +}; + static struct pcf21xx_config pcf21xx_cfg[] = { [PCF2127] = { .type = PCF2127, @@ -746,6 +888,53 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .attrs = pcf2127_attrs, }, }, + [PCF2131] = { + .type = PCF2131, + .max_register = 0x36, + .has_nvmem = 0, + .has_bit_wd_ctl_cd0 = 0, + .reg_time_base = PCF2131_REG_TIME_BASE, + .regs_alarm_base = PCF2131_REG_ALARM_BASE, + .reg_wd_ctl = PCF2131_REG_WD_CTL, + .reg_wd_val = PCF2131_REG_WD_VAL, + .reg_clkout = PCF2131_REG_CLKOUT, + .ts_count = 4, + .ts[0] = { + .reg_base = PCF2131_REG_TS1_BASE, + .gnd_detect_reg = PCF2131_REG_CTRL4, + .gnd_detect_bit = PCF2131_BIT_CTRL4_TSF1, + .inter_detect_bit = 0, + .ie_reg = PCF2131_REG_CTRL5, + .ie_bit = PCF2131_BIT_CTRL5_TSIE1, + }, + .ts[1] = { + .reg_base = PCF2131_REG_TS2_BASE, + .gnd_detect_reg = PCF2131_REG_CTRL4, + .gnd_detect_bit = PCF2131_BIT_CTRL4_TSF2, + .inter_detect_bit = 0, + .ie_reg = PCF2131_REG_CTRL5, + .ie_bit = PCF2131_BIT_CTRL5_TSIE2, + }, + .ts[2] = { + .reg_base = PCF2131_REG_TS3_BASE, + .gnd_detect_reg = PCF2131_REG_CTRL4, + .gnd_detect_bit = PCF2131_BIT_CTRL4_TSF3, + .inter_detect_bit = 0, + .ie_reg = PCF2131_REG_CTRL5, + .ie_bit = PCF2131_BIT_CTRL5_TSIE3, + }, + .ts[3] = { + .reg_base = PCF2131_REG_TS4_BASE, + .gnd_detect_reg = PCF2131_REG_CTRL4, + .gnd_detect_bit = PCF2131_BIT_CTRL4_TSF4, + .inter_detect_bit = 0, + .ie_reg = PCF2131_REG_CTRL5, + .ie_bit = PCF2131_BIT_CTRL5_TSIE4, + }, + .attribute_group = { + .attrs = pcf2131_attrs, + }, + }, }; /* @@ -893,7 +1082,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, * Watchdog timer enabled and reset pin /RST activated when timed out. * Select 1Hz clock source for watchdog timer. * Note: Countdown timer disabled and not available. - * For pca2129, pcf2129, only bit[7] is for Symbol WD_CD + * For pca2129, pcf2129 and pcf2131, only bit[7] is for Symbol WD_CD * of register watchdg_tim_ctl. The bit[6] is labeled * as T. Bits labeled as T must always be written with * logic 0. @@ -953,6 +1142,7 @@ static const struct of_device_id pcf2127_of_match[] = { { .compatible = "nxp,pcf2127", .data = &pcf21xx_cfg[PCF2127] }, { .compatible = "nxp,pcf2129", .data = &pcf21xx_cfg[PCF2129] }, { .compatible = "nxp,pca2129", .data = &pcf21xx_cfg[PCF2129] }, + { .compatible = "nxp,pcf2131", .data = &pcf21xx_cfg[PCF2131] }, {} }; MODULE_DEVICE_TABLE(of, pcf2127_of_match); @@ -1040,6 +1230,7 @@ static const struct i2c_device_id pcf2127_i2c_id[] = { { "pcf2127", PCF2127 }, { "pcf2129", PCF2129 }, { "pca2129", PCF2129 }, + { "pcf2131", PCF2131 }, { } }; MODULE_DEVICE_TABLE(i2c, pcf2127_i2c_id); @@ -1161,6 +1352,7 @@ static const struct spi_device_id pcf2127_spi_id[] = { { "pcf2127", PCF2127 }, { "pcf2129", PCF2129 }, { "pca2129", PCF2129 }, + { "pcf2131", PCF2131 }, { } }; MODULE_DEVICE_TABLE(spi, pcf2127_spi_id); @@ -1225,5 +1417,5 @@ static void __exit pcf2127_exit(void) module_exit(pcf2127_exit) MODULE_AUTHOR("Renaud Cerrato "); -MODULE_DESCRIPTION("NXP PCF2127/29 RTC driver"); +MODULE_DESCRIPTION("NXP PCF2127/29/31 RTC driver"); MODULE_LICENSE("GPL v2"); -- GitLab From e1849b8fcdfaa71f2e8f9376c9568877ff2bf52b Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:55 -0400 Subject: [PATCH 0451/3445] rtc: pcf2127: add support for PCF2131 interrupts on output INT_A The PCF2127 and PCF2129 have one output interrupt pin. The PCF2131 has two, named INT_A and INT_B. The hardware support that any interrupt source can be routed to either one or both of them. Force all interrupt sources to go to the INT A pin. Support to route any interrupt source to INT A/B pins is not supported by this driver at the moment. Signed-off-by: Hugo Villeneuve Reviewed-by: Bruno Thomsen Link: https://lore.kernel.org/r/20230622145800.2442116-13-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 8c2ad9eac861b..83dcb1e43abb0 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -179,6 +179,7 @@ struct pcf21xx_config { int max_register; unsigned int has_nvmem:1; unsigned int has_bit_wd_ctl_cd0:1; + unsigned int has_int_a_b:1; /* PCF2131 supports two interrupt outputs. */ u8 reg_time_base; /* Time/date base register. */ u8 regs_alarm_base; /* Alarm function base registers. */ u8 reg_wd_ctl; /* Watchdog control register. */ @@ -845,6 +846,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .max_register = 0x1d, .has_nvmem = 1, .has_bit_wd_ctl_cd0 = 1, + .has_int_a_b = 0, .reg_time_base = PCF2127_REG_TIME_BASE, .regs_alarm_base = PCF2127_REG_ALARM_BASE, .reg_wd_ctl = PCF2127_REG_WD_CTL, @@ -869,6 +871,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .max_register = 0x19, .has_nvmem = 0, .has_bit_wd_ctl_cd0 = 0, + .has_int_a_b = 0, .reg_time_base = PCF2127_REG_TIME_BASE, .regs_alarm_base = PCF2127_REG_ALARM_BASE, .reg_wd_ctl = PCF2127_REG_WD_CTL, @@ -893,6 +896,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .max_register = 0x36, .has_nvmem = 0, .has_bit_wd_ctl_cd0 = 0, + .has_int_a_b = 1, .reg_time_base = PCF2131_REG_TIME_BASE, .regs_alarm_base = PCF2131_REG_ALARM_BASE, .reg_wd_ctl = PCF2131_REG_WD_CTL, @@ -989,6 +993,28 @@ static int pcf2127_enable_ts(struct device *dev, int ts_id) return ret; } +/* Route all interrupt sources to INT A pin. */ +static int pcf2127_configure_interrupt_pins(struct device *dev) +{ + struct pcf2127 *pcf2127 = dev_get_drvdata(dev); + int ret; + + /* Mask bits need to be cleared to enable corresponding + * interrupt source. + */ + ret = regmap_write(pcf2127->regmap, + PCF2131_REG_INT_A_MASK1, 0); + if (ret) + return ret; + + ret = regmap_write(pcf2127->regmap, + PCF2131_REG_INT_A_MASK2, 0); + if (ret) + return ret; + + return ret; +} + static int pcf2127_probe(struct device *dev, struct regmap *regmap, int alarm_irq, const char *name, const struct pcf21xx_config *config) { @@ -1047,6 +1073,15 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, set_bit(RTC_FEATURE_ALARM, pcf2127->rtc->features); } + if (pcf2127->cfg->has_int_a_b) { + /* Configure int A/B pins, independently of alarm_irq. */ + ret = pcf2127_configure_interrupt_pins(dev); + if (ret) { + dev_err(dev, "failed to configure interrupt pins\n"); + return ret; + } + } + if (pcf2127->cfg->has_nvmem) { struct nvmem_config nvmem_cfg = { .priv = pcf2127, -- GitLab From 3d715ebaf006bd5a495e9a717cf0fc5c260ee738 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:56 -0400 Subject: [PATCH 0452/3445] rtc: pcf2127: adapt time/date registers write sequence for PCF2131 The sequence for updating the time/date registers is slightly different between PCF2127/29 and PCF2131. For PCF2127/29, during write operations, the time counting circuits (memory locations 03h through 09h) are automatically blocked. For PCF2131, time/date registers write access requires setting the STOP bit and sending the clear prescaler instruction (CPR). STOP then needs to be released once write operation is completed. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-14-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 83dcb1e43abb0..f6a549b1f743b 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -33,6 +33,7 @@ #define PCF2127_REG_CTRL1 0x00 #define PCF2127_BIT_CTRL1_POR_OVRD BIT(3) #define PCF2127_BIT_CTRL1_TSF1 BIT(4) +#define PCF2127_BIT_CTRL1_STOP BIT(5) /* Control register 2 */ #define PCF2127_REG_CTRL2 0x01 #define PCF2127_BIT_CTRL2_AIE BIT(1) @@ -280,13 +281,45 @@ static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm) /* year */ buf[i++] = bin2bcd(tm->tm_year - 100); - /* write register's data */ + /* Write access to time registers: + * PCF2127/29: no special action required. + * PCF2131: requires setting the STOP and CPR bits. STOP bit needs to + * be cleared after time registers are updated. + */ + if (pcf2127->cfg->type == PCF2131) { + err = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1, + PCF2127_BIT_CTRL1_STOP, + PCF2127_BIT_CTRL1_STOP); + if (err) { + dev_dbg(dev, "setting STOP bit failed\n"); + return err; + } + + err = regmap_write(pcf2127->regmap, PCF2131_REG_SR_RESET, + PCF2131_SR_RESET_CPR_CMD); + if (err) { + dev_dbg(dev, "sending CPR cmd failed\n"); + return err; + } + } + + /* write time register's data */ err = regmap_bulk_write(pcf2127->regmap, pcf2127->cfg->reg_time_base, buf, i); if (err) { dev_dbg(dev, "%s: err=%d", __func__, err); return err; } + if (pcf2127->cfg->type == PCF2131) { + /* Clear STOP bit (PCF2131 only) after write is completed. */ + err = regmap_update_bits(pcf2127->regmap, PCF2127_REG_CTRL1, + PCF2127_BIT_CTRL1_STOP, 0); + if (err) { + dev_dbg(dev, "clearing STOP bit failed\n"); + return err; + } + } + return 0; } -- GitLab From adb9675d74e403537150f025ed2b7a2e1ed0a7b4 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:57 -0400 Subject: [PATCH 0453/3445] rtc: pcf2127: support generic watchdog timing configuration Introduce in the configuration structure two new values to hold the watchdog clock source and the min_hw_heartbeat_ms value. The minimum and maximum timeout values are automatically computed from the watchdog clock source value for each variant. The PCF2131 has no 1Hz watchdog clock source, as is the case for PCF2127/29. The next best choice is using a 1/4Hz clock, giving a watchdog timeout range between 4 and 1016s. By using the same register configuration as for the PCF2127/29, the 1/4Hz clock source is selected. Note: the PCF2127 datasheet gives a min/max range between 1 and 255s, but it should be between 2 and 254s, because the watchdog is triggered when the timer value reaches 1, not 0. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-15-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 64 +++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index f6a549b1f743b..59c0dcfed5c80 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -80,9 +80,14 @@ /* Watchdog timer value constants */ #define PCF2127_WD_VAL_STOP 0 -#define PCF2127_WD_VAL_MIN 2 -#define PCF2127_WD_VAL_MAX 255 -#define PCF2127_WD_VAL_DEFAULT 60 +/* PCF2127/29 watchdog timer value constants */ +#define PCF2127_WD_CLOCK_HZ_X1000 1000 /* 1Hz */ +#define PCF2127_WD_MIN_HW_HEARTBEAT_MS 500 +/* PCF2131 watchdog timer value constants */ +#define PCF2131_WD_CLOCK_HZ_X1000 250 /* 1/4Hz */ +#define PCF2131_WD_MIN_HW_HEARTBEAT_MS 4000 + +#define PCF2127_WD_DEFAULT_TIMEOUT_S 60 /* Mask for currently enabled interrupts */ #define PCF2127_CTRL1_IRQ_MASK (PCF2127_BIT_CTRL1_TSF1) @@ -186,6 +191,8 @@ struct pcf21xx_config { u8 reg_wd_ctl; /* Watchdog control register. */ u8 reg_wd_val; /* Watchdog value register. */ u8 reg_clkout; /* Clkout register. */ + int wdd_clock_hz_x1000; /* Watchdog clock in Hz multiplicated by 1000 */ + int wdd_min_hw_heartbeat_ms; unsigned int ts_count; struct pcf21xx_ts_config ts[PCF2127_MAX_TS_SUPPORTED]; struct attribute_group attribute_group; @@ -389,9 +396,16 @@ static int pcf2127_nvmem_write(void *priv, unsigned int offset, static int pcf2127_wdt_ping(struct watchdog_device *wdd) { + int wd_val; struct pcf2127 *pcf2127 = watchdog_get_drvdata(wdd); - return regmap_write(pcf2127->regmap, pcf2127->cfg->reg_wd_val, wdd->timeout); + /* + * Compute counter value of WATCHDG_TIM_VAL to obtain desired period + * in seconds, depending on the source clock frequency. + */ + wd_val = ((wdd->timeout * pcf2127->cfg->wdd_clock_hz_x1000) / 1000) + 1; + + return regmap_write(pcf2127->regmap, pcf2127->cfg->reg_wd_val, wd_val); } /* @@ -453,6 +467,23 @@ static const struct watchdog_ops pcf2127_watchdog_ops = { .set_timeout = pcf2127_wdt_set_timeout, }; +/* + * Compute watchdog period, t, in seconds, from the WATCHDG_TIM_VAL register + * value, n, and the clock frequency, f1000, in Hz x 1000. + * + * The PCF2127/29 datasheet gives t as: + * t = n / f + * The PCF2131 datasheet gives t as: + * t = (n - 1) / f + * For both variants, the watchdog is triggered when the WATCHDG_TIM_VAL reaches + * the value 1, and not zero. Consequently, the equation from the PCF2131 + * datasheet seems to be the correct one for both variants. + */ +static int pcf2127_watchdog_get_period(int n, int f1000) +{ + return (1000 * (n - 1)) / f1000; +} + static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127) { u32 wdd_timeout; @@ -465,10 +496,19 @@ static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127) pcf2127->wdd.parent = dev; pcf2127->wdd.info = &pcf2127_wdt_info; pcf2127->wdd.ops = &pcf2127_watchdog_ops; - pcf2127->wdd.min_timeout = PCF2127_WD_VAL_MIN; - pcf2127->wdd.max_timeout = PCF2127_WD_VAL_MAX; - pcf2127->wdd.timeout = PCF2127_WD_VAL_DEFAULT; - pcf2127->wdd.min_hw_heartbeat_ms = 500; + + pcf2127->wdd.min_timeout = + pcf2127_watchdog_get_period( + 2, pcf2127->cfg->wdd_clock_hz_x1000); + pcf2127->wdd.max_timeout = + pcf2127_watchdog_get_period( + 255, pcf2127->cfg->wdd_clock_hz_x1000); + pcf2127->wdd.timeout = PCF2127_WD_DEFAULT_TIMEOUT_S; + + dev_dbg(dev, "%s clock = %d Hz / 1000\n", __func__, + pcf2127->cfg->wdd_clock_hz_x1000); + + pcf2127->wdd.min_hw_heartbeat_ms = pcf2127->cfg->wdd_min_hw_heartbeat_ms; pcf2127->wdd.status = WATCHDOG_NOWAYOUT_INIT_STATUS; watchdog_set_drvdata(&pcf2127->wdd, pcf2127); @@ -885,6 +925,8 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .reg_wd_ctl = PCF2127_REG_WD_CTL, .reg_wd_val = PCF2127_REG_WD_VAL, .reg_clkout = PCF2127_REG_CLKOUT, + .wdd_clock_hz_x1000 = PCF2127_WD_CLOCK_HZ_X1000, + .wdd_min_hw_heartbeat_ms = PCF2127_WD_MIN_HW_HEARTBEAT_MS, .ts_count = 1, .ts[0] = { .reg_base = PCF2127_REG_TS1_BASE, @@ -910,6 +952,8 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .reg_wd_ctl = PCF2127_REG_WD_CTL, .reg_wd_val = PCF2127_REG_WD_VAL, .reg_clkout = PCF2127_REG_CLKOUT, + .wdd_clock_hz_x1000 = PCF2127_WD_CLOCK_HZ_X1000, + .wdd_min_hw_heartbeat_ms = PCF2127_WD_MIN_HW_HEARTBEAT_MS, .ts_count = 1, .ts[0] = { .reg_base = PCF2127_REG_TS1_BASE, @@ -935,6 +979,8 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .reg_wd_ctl = PCF2131_REG_WD_CTL, .reg_wd_val = PCF2131_REG_WD_VAL, .reg_clkout = PCF2131_REG_CLKOUT, + .wdd_clock_hz_x1000 = PCF2131_WD_CLOCK_HZ_X1000, + .wdd_min_hw_heartbeat_ms = PCF2131_WD_MIN_HW_HEARTBEAT_MS, .ts_count = 4, .ts[0] = { .reg_base = PCF2131_REG_TS1_BASE, @@ -1148,7 +1194,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, /* * Watchdog timer enabled and reset pin /RST activated when timed out. - * Select 1Hz clock source for watchdog timer. + * Select 1Hz clock source for watchdog timer (1/4Hz for PCF2131). * Note: Countdown timer disabled and not available. * For pca2129, pcf2129 and pcf2131, only bit[7] is for Symbol WD_CD * of register watchdg_tim_ctl. The bit[6] is labeled -- GitLab From 081602a1d85b1fd7ad9ea298cffb4e5ad5296952 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:58 -0400 Subject: [PATCH 0454/3445] rtc: pcf2127: add flag for watchdog register value read support The watchdog value register cannot be read on the PCF2131 after being set. Add a new flag to identify which variant has read access to this register, and use this flag to selectively test if watchdog timer was started by bootloader. Signed-off-by: Hugo Villeneuve Reviewed-by: Bruno Thomsen Link: https://lore.kernel.org/r/20230622145800.2442116-16-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 59c0dcfed5c80..3acab5a19aba5 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -185,6 +185,7 @@ struct pcf21xx_config { int max_register; unsigned int has_nvmem:1; unsigned int has_bit_wd_ctl_cd0:1; + unsigned int wd_val_reg_readable:1; /* If watchdog value register can be read. */ unsigned int has_int_a_b:1; /* PCF2131 supports two interrupt outputs. */ u8 reg_time_base; /* Time/date base register. */ u8 regs_alarm_base; /* Alarm function base registers. */ @@ -486,7 +487,6 @@ static int pcf2127_watchdog_get_period(int n, int f1000) static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127) { - u32 wdd_timeout; int ret; if (!IS_ENABLED(CONFIG_WATCHDOG) || @@ -514,12 +514,17 @@ static int pcf2127_watchdog_init(struct device *dev, struct pcf2127 *pcf2127) watchdog_set_drvdata(&pcf2127->wdd, pcf2127); /* Test if watchdog timer is started by bootloader */ - ret = regmap_read(pcf2127->regmap, pcf2127->cfg->reg_wd_val, &wdd_timeout); - if (ret) - return ret; + if (pcf2127->cfg->wd_val_reg_readable) { + u32 wdd_timeout; + + ret = regmap_read(pcf2127->regmap, pcf2127->cfg->reg_wd_val, + &wdd_timeout); + if (ret) + return ret; - if (wdd_timeout) - set_bit(WDOG_HW_RUNNING, &pcf2127->wdd.status); + if (wdd_timeout) + set_bit(WDOG_HW_RUNNING, &pcf2127->wdd.status); + } return devm_watchdog_register_device(dev, &pcf2127->wdd); } @@ -919,6 +924,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .max_register = 0x1d, .has_nvmem = 1, .has_bit_wd_ctl_cd0 = 1, + .wd_val_reg_readable = 1, .has_int_a_b = 0, .reg_time_base = PCF2127_REG_TIME_BASE, .regs_alarm_base = PCF2127_REG_ALARM_BASE, @@ -946,6 +952,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .max_register = 0x19, .has_nvmem = 0, .has_bit_wd_ctl_cd0 = 0, + .wd_val_reg_readable = 1, .has_int_a_b = 0, .reg_time_base = PCF2127_REG_TIME_BASE, .regs_alarm_base = PCF2127_REG_ALARM_BASE, @@ -973,6 +980,7 @@ static struct pcf21xx_config pcf21xx_cfg[] = { .max_register = 0x36, .has_nvmem = 0, .has_bit_wd_ctl_cd0 = 0, + .wd_val_reg_readable = 0, .has_int_a_b = 1, .reg_time_base = PCF2131_REG_TIME_BASE, .regs_alarm_base = PCF2131_REG_ALARM_BASE, -- GitLab From e9a5a1b418dd9a82d1de71e82ec64ad195b5300a Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:57:59 -0400 Subject: [PATCH 0455/3445] rtc: pcf2127: add UIE support for PCF2131 The PCF2127/29 do NOT support alarms with a 1 second resolution, but the PCF2131 does. Signed-off-by: Hugo Villeneuve Link: https://lore.kernel.org/r/20230622145800.2442116-17-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 3acab5a19aba5..78141bb06ab0b 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -1128,8 +1128,16 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, pcf2127->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; pcf2127->rtc->range_max = RTC_TIMESTAMP_END_2099; pcf2127->rtc->set_start_time = true; /* Sets actual start to 1970 */ - set_bit(RTC_FEATURE_ALARM_RES_2S, pcf2127->rtc->features); - clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf2127->rtc->features); + + /* + * PCF2127/29 do not work correctly when setting alarms at 1s intervals. + * PCF2131 is ok. + */ + if (pcf2127->cfg->type == PCF2127 || pcf2127->cfg->type == PCF2129) { + set_bit(RTC_FEATURE_ALARM_RES_2S, pcf2127->rtc->features); + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf2127->rtc->features); + } + clear_bit(RTC_FEATURE_ALARM, pcf2127->rtc->features); if (alarm_irq > 0) { -- GitLab From 2080e08460c41c6d432575132868fdf076768c92 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 22 Jun 2023 10:58:00 -0400 Subject: [PATCH 0456/3445] dt-bindings: rtc: pcf2127: add PCF2131 Add support for new NXP RTC PCF2131. Signed-off-by: Hugo Villeneuve Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230622145800.2442116-18-hugo@hugovil.com Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/nxp,pcf2127.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/rtc/nxp,pcf2127.yaml b/Documentation/devicetree/bindings/rtc/nxp,pcf2127.yaml index bcb2300276227..2d9fe5a75b067 100644 --- a/Documentation/devicetree/bindings/rtc/nxp,pcf2127.yaml +++ b/Documentation/devicetree/bindings/rtc/nxp,pcf2127.yaml @@ -18,6 +18,7 @@ properties: - nxp,pca2129 - nxp,pcf2127 - nxp,pcf2129 + - nxp,pcf2131 reg: maxItems: 1 -- GitLab From f69cb2d6034ddf8dae6848d29b9d4efba8cd4df9 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 5 Jul 2023 19:43:51 +0200 Subject: [PATCH 0457/3445] rtc: stm32: use the proper register sequence to read date/time Date and time are read from two separate RTC registers. To ensure consistency between the two registers, reading the time register locks the values in the shadow date register until the date register is read. Thus, the whole date/time read requires reading the time register first, followed by reading the date register. If the reads are done in reversed order, the shadow date register will remain locked until a future read operation. The future read will read the former date value that could be already invalid. Fix the read order of date/time registers in stm32_rtc_valid_alrm() Signed-off-by: Antonio Borneo Signed-off-by: Valentin Caron Link: https://lore.kernel.org/r/20230705174357.353616-2-valentin.caron@foss.st.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index 3d36e11cff80c..abb77ad774a1c 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -429,8 +429,8 @@ static int stm32_rtc_valid_alrm(struct stm32_rtc *rtc, struct rtc_time *tm) { const struct stm32_rtc_registers *regs = &rtc->data->regs; int cur_day, cur_mon, cur_year, cur_hour, cur_min, cur_sec; - unsigned int dr = readl_relaxed(rtc->base + regs->dr); unsigned int tr = readl_relaxed(rtc->base + regs->tr); + unsigned int dr = readl_relaxed(rtc->base + regs->dr); cur_day = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT; cur_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT; -- GitLab From 1c18b8ec52396af6a6e20cd3450dc9bff0781ab8 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 5 Jul 2023 19:43:52 +0200 Subject: [PATCH 0458/3445] rtc: stm32: don't stop time counter if not needed RTC counters are stopped when INIT bit in ISR register is set and start counting from the (eventual) new value when INIT is reset. In stm32_rtc_init(), called during probe, the INIT bit is set to program the prescaler and the 24h mode. This halts the RTC counter at each probe tentative causing the RTC time to loose from 0.3s to 0.8s at each kernel boot. If the RTC is battery powered, both prescaler value and 24h mode are kept during power cycle and there is no need to program them again. Check if the desired prescaler value and the 24h mode are already programmed, then skip reprogramming them to avoid halting the time counter. Signed-off-by: Antonio Borneo Signed-off-by: Valentin Caron Link: https://lore.kernel.org/r/20230705174357.353616-3-valentin.caron@foss.st.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stm32.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index abb77ad774a1c..bd7a59a07537d 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -628,7 +628,7 @@ static int stm32_rtc_init(struct platform_device *pdev, const struct stm32_rtc_registers *regs = &rtc->data->regs; unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr; unsigned int rate; - int ret = 0; + int ret; rate = clk_get_rate(rtc->rtc_ck); @@ -656,6 +656,20 @@ static int stm32_rtc_init(struct platform_device *pdev, "fast" : "slow"); } + cr = readl_relaxed(rtc->base + regs->cr); + + prer = readl_relaxed(rtc->base + regs->prer); + prer &= STM32_RTC_PRER_PRED_S | STM32_RTC_PRER_PRED_A; + + pred_s = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & + STM32_RTC_PRER_PRED_S; + pred_a = (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & + STM32_RTC_PRER_PRED_A; + + /* quit if there is nothing to initialize */ + if ((cr & STM32_RTC_CR_FMT) == 0 && prer == (pred_s | pred_a)) + return 0; + stm32_rtc_wpr_unlock(rtc); ret = stm32_rtc_enter_init_mode(rtc); @@ -665,13 +679,10 @@ static int stm32_rtc_init(struct platform_device *pdev, goto end; } - prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & STM32_RTC_PRER_PRED_S; - writel_relaxed(prer, rtc->base + regs->prer); - prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A; - writel_relaxed(prer, rtc->base + regs->prer); + writel_relaxed(pred_s, rtc->base + regs->prer); + writel_relaxed(pred_a | pred_s, rtc->base + regs->prer); /* Force 24h time format */ - cr = readl_relaxed(rtc->base + regs->cr); cr &= ~STM32_RTC_CR_FMT; writel_relaxed(cr, rtc->base + regs->cr); -- GitLab From 2487925731b75961cf4b7d1d0d28d204b63787b9 Mon Sep 17 00:00:00 2001 From: Christophe Guibout Date: Wed, 5 Jul 2023 19:43:53 +0200 Subject: [PATCH 0459/3445] rtc: stm32: improve rtc precision The rtc is used to update the stgen counter on wake up from low power modes, so it needs to be as much accurate as possible. The maximization of asynchronous divider leads to a 4ms rtc precision clock. By decreasing pred_a to 0, it will have pred_s=32767 (when need_accuracy is true), so stgen clock becomes more accurate with 30us precision. Nevertheless this will leads to an increase of power consumption. Signed-off-by: Christophe Guibout Signed-off-by: Valentin Caron Link: https://lore.kernel.org/r/20230705174357.353616-4-valentin.caron@foss.st.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stm32.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index bd7a59a07537d..cad88668bcfb3 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -114,6 +114,7 @@ struct stm32_rtc_data { void (*clear_events)(struct stm32_rtc *rtc, unsigned int flags); bool has_pclk; bool need_dbp; + bool need_accuracy; }; struct stm32_rtc { @@ -545,6 +546,7 @@ static void stm32_rtc_clear_events(struct stm32_rtc *rtc, static const struct stm32_rtc_data stm32_rtc_data = { .has_pclk = false, .need_dbp = true, + .need_accuracy = false, .regs = { .tr = 0x00, .dr = 0x04, @@ -566,6 +568,7 @@ static const struct stm32_rtc_data stm32_rtc_data = { static const struct stm32_rtc_data stm32h7_rtc_data = { .has_pclk = true, .need_dbp = true, + .need_accuracy = false, .regs = { .tr = 0x00, .dr = 0x04, @@ -596,6 +599,7 @@ static void stm32mp1_rtc_clear_events(struct stm32_rtc *rtc, static const struct stm32_rtc_data stm32mp1_data = { .has_pclk = true, .need_dbp = false, + .need_accuracy = true, .regs = { .tr = 0x00, .dr = 0x04, @@ -636,11 +640,25 @@ static int stm32_rtc_init(struct platform_device *pdev, pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT; pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT; - for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) { - pred_s = (rate / (pred_a + 1)) - 1; + if (rate > (pred_a_max + 1) * (pred_s_max + 1)) { + dev_err(&pdev->dev, "rtc_ck rate is too high: %dHz\n", rate); + return -EINVAL; + } + + if (rtc->data->need_accuracy) { + for (pred_a = 0; pred_a <= pred_a_max; pred_a++) { + pred_s = (rate / (pred_a + 1)) - 1; - if (((pred_s + 1) * (pred_a + 1)) == rate) - break; + if (pred_s <= pred_s_max && ((pred_s + 1) * (pred_a + 1)) == rate) + break; + } + } else { + for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) { + pred_s = (rate / (pred_a + 1)) - 1; + + if (((pred_s + 1) * (pred_a + 1)) == rate) + break; + } } /* -- GitLab From 95f7679c3ab2d032d935692426b6d9f7e681fd60 Mon Sep 17 00:00:00 2001 From: Valentin Caron Date: Wed, 5 Jul 2023 19:43:54 +0200 Subject: [PATCH 0460/3445] rtc: stm32: don't print an error on probe deferral Change stm32-rtc driver to not generate an error message when device probe operation is deferred for a clock. Signed-off-by: Etienne Carriere Signed-off-by: Valentin Caron Link: https://lore.kernel.org/r/20230705174357.353616-5-valentin.caron@foss.st.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stm32.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index cad88668bcfb3..5ebf0b8e75f97 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -759,16 +760,13 @@ static int stm32_rtc_probe(struct platform_device *pdev) rtc->rtc_ck = devm_clk_get(&pdev->dev, NULL); } else { rtc->pclk = devm_clk_get(&pdev->dev, "pclk"); - if (IS_ERR(rtc->pclk)) { - dev_err(&pdev->dev, "no pclk clock"); - return PTR_ERR(rtc->pclk); - } + if (IS_ERR(rtc->pclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(rtc->pclk), "no pclk clock"); + rtc->rtc_ck = devm_clk_get(&pdev->dev, "rtc_ck"); } - if (IS_ERR(rtc->rtc_ck)) { - dev_err(&pdev->dev, "no rtc_ck clock"); - return PTR_ERR(rtc->rtc_ck); - } + if (IS_ERR(rtc->rtc_ck)) + return dev_err_probe(&pdev->dev, PTR_ERR(rtc->rtc_ck), "no rtc_ck clock"); if (rtc->data->has_pclk) { ret = clk_prepare_enable(rtc->pclk); -- GitLab From fb9a7e5360dc8089097337a9685f6fed350a310f Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Wed, 5 Jul 2023 19:43:55 +0200 Subject: [PATCH 0461/3445] rtc: stm32: change PM callbacks to "_noirq()" The RTC driver stops the RTCAPB clock during suspend, but the irq handler from RTC is called before starting clock. Then we are blocked while accessing RTC registers. We changes PM callbacks to '_no_irq()' to disable irq during resume callback and so irq handler will be called after the enable of RTCAPB clock. Signed-off-by: Gabriel Fernandez Signed-off-by: Valentin Caron Link: https://lore.kernel.org/r/20230705174357.353616-6-valentin.caron@foss.st.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stm32.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index 5ebf0b8e75f97..17e5498067847 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -919,8 +919,9 @@ static int stm32_rtc_resume(struct device *dev) } #endif -static SIMPLE_DEV_PM_OPS(stm32_rtc_pm_ops, - stm32_rtc_suspend, stm32_rtc_resume); +static const struct dev_pm_ops stm32_rtc_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_rtc_suspend, stm32_rtc_resume) +}; static struct platform_driver stm32_rtc_driver = { .probe = stm32_rtc_probe, -- GitLab From 46828a5f89044b8e057f6bbb50ae2bac926a0fa2 Mon Sep 17 00:00:00 2001 From: Valentin Caron Date: Wed, 5 Jul 2023 19:43:56 +0200 Subject: [PATCH 0462/3445] rtc: stm32: fix issues of stm32_rtc_valid_alrm function stm32_rtc_valid_alrm function has some issues : - arithmetical operations are impossible on BCD values - "cur_mon + 1" can overflow - the use case with the next month, the same day/hour/minutes went wrong To solve that, we prefer to use timestamp comparison. e.g. : On 5 Dec. 2021, the alarm limit is 5 Jan. 2022 (+31 days) On 31 Jan 2021, the alarm limit is 28 Feb. 2022 (+28 days) Signed-off-by: Valentin Caron Link: https://lore.kernel.org/r/20230705174357.353616-7-valentin.caron@foss.st.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stm32.c | 61 ++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index 17e5498067847..836d39a124dd6 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -90,6 +90,9 @@ /* Max STM32 RTC register offset is 0x3FC */ #define UNDEF_REG 0xFFFF +/* STM32 RTC driver time helpers */ +#define SEC_PER_DAY (24 * 60 * 60) + struct stm32_rtc; struct stm32_rtc_registers { @@ -427,40 +430,42 @@ static int stm32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) return 0; } -static int stm32_rtc_valid_alrm(struct stm32_rtc *rtc, struct rtc_time *tm) +static int stm32_rtc_valid_alrm(struct device *dev, struct rtc_time *tm) { - const struct stm32_rtc_registers *regs = &rtc->data->regs; - int cur_day, cur_mon, cur_year, cur_hour, cur_min, cur_sec; - unsigned int tr = readl_relaxed(rtc->base + regs->tr); - unsigned int dr = readl_relaxed(rtc->base + regs->dr); - - cur_day = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT; - cur_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT; - cur_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT; - cur_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT; - cur_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT; - cur_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT; + static struct rtc_time now; + time64_t max_alarm_time64; + int max_day_forward; + int next_month; + int next_year; /* * Assuming current date is M-D-Y H:M:S. * RTC alarm can't be set on a specific month and year. * So the valid alarm range is: * M-D-Y H:M:S < alarm <= (M+1)-D-Y H:M:S - * with a specific case for December... */ - if ((((tm->tm_year > cur_year) && - (tm->tm_mon == 0x1) && (cur_mon == 0x12)) || - ((tm->tm_year == cur_year) && - (tm->tm_mon <= cur_mon + 1))) && - ((tm->tm_mday > cur_day) || - ((tm->tm_mday == cur_day) && - ((tm->tm_hour > cur_hour) || - ((tm->tm_hour == cur_hour) && (tm->tm_min > cur_min)) || - ((tm->tm_hour == cur_hour) && (tm->tm_min == cur_min) && - (tm->tm_sec >= cur_sec)))))) - return 0; + stm32_rtc_read_time(dev, &now); + + /* + * Find the next month and the year of the next month. + * Note: tm_mon and next_month are from 0 to 11 + */ + next_month = now.tm_mon + 1; + if (next_month == 12) { + next_month = 0; + next_year = now.tm_year + 1; + } else { + next_year = now.tm_year; + } - return -EINVAL; + /* Find the maximum limit of alarm in days. */ + max_day_forward = rtc_month_days(now.tm_mon, now.tm_year) + - now.tm_mday + + min(rtc_month_days(next_month, next_year), now.tm_mday); + + /* Convert to timestamp and compare the alarm time and its upper limit */ + max_alarm_time64 = rtc_tm_to_time64(&now) + max_day_forward * SEC_PER_DAY; + return rtc_tm_to_time64(tm) <= max_alarm_time64 ? 0 : -EINVAL; } static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) @@ -471,17 +476,17 @@ static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) unsigned int cr, isr, alrmar; int ret = 0; - tm2bcd(tm); - /* * RTC alarm can't be set on a specific date, unless this date is * up to the same day of month next month. */ - if (stm32_rtc_valid_alrm(rtc, tm) < 0) { + if (stm32_rtc_valid_alrm(dev, tm) < 0) { dev_err(dev, "Alarm can be set only on upcoming month.\n"); return -EINVAL; } + tm2bcd(tm); + alrmar = 0; /* tm_year and tm_mon are not used because not supported by RTC */ alrmar |= (tm->tm_mday << STM32_RTC_ALRMXR_DATE_SHIFT) & -- GitLab From 650915ecd8f8cbb58e1ef55430f9e15ae03fd7d8 Mon Sep 17 00:00:00 2001 From: Valentin Caron Date: Wed, 5 Jul 2023 19:43:57 +0200 Subject: [PATCH 0463/3445] rtc: stm32: fix unnecessary parentheses Fix a few style issues reported by checkpatch.pl: - Unnecessary parentheses - Lines should not end with a '(' Signed-off-by: Valentin Caron Link: https://lore.kernel.org/r/20230705174357.353616-8-valentin.caron@foss.st.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stm32.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index 836d39a124dd6..85689192fa7ae 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -163,10 +163,9 @@ static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc) * slowest rtc_ck frequency may be 32kHz and highest should be * 1MHz, we poll every 10 us with a timeout of 100ms. */ - return readl_relaxed_poll_timeout_atomic( - rtc->base + regs->isr, - isr, (isr & STM32_RTC_ISR_INITF), - 10, 100000); + return readl_relaxed_poll_timeout_atomic(rtc->base + regs->isr, isr, + (isr & STM32_RTC_ISR_INITF), + 10, 100000); } return 0; @@ -671,7 +670,7 @@ static int stm32_rtc_init(struct platform_device *pdev, * Can't find a 1Hz, so give priority to RTC power consumption * by choosing the higher possible value for prediv_a */ - if ((pred_s > pred_s_max) || (pred_a > pred_a_max)) { + if (pred_s > pred_s_max || pred_a > pred_a_max) { pred_a = pred_a_max; pred_s = (rate / (pred_a + 1)) - 1; -- GitLab From b7f73b6e921b457a222e86cf53fe3950c6b5aed5 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Mon, 10 Jul 2023 12:47:47 +0100 Subject: [PATCH 0464/3445] rtc: isl1208: Simplify probe() Simplify the probe() by replacing of_device_get_match_data() and i2c_match_id() by i2c_get_match_data() as we have similar I2C and DT-based matching table. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230710114747.106496-1-biju.das.jz@bp.renesas.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl1208.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index b0712b4e36489..57e77b55e4842 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -862,17 +862,9 @@ isl1208_probe(struct i2c_client *client) i2c_set_clientdata(client, isl1208); /* Determine which chip we have */ - if (client->dev.of_node) { - isl1208->config = of_device_get_match_data(&client->dev); - if (!isl1208->config) - return -ENODEV; - } else { - const struct i2c_device_id *id = i2c_match_id(isl1208_id, client); - - if (!id) - return -ENODEV; - isl1208->config = (struct isl1208_config *)id->driver_data; - } + isl1208->config = i2c_get_match_data(client); + if (!isl1208->config) + return -ENODEV; rc = isl1208_clk_present(client, "xin"); if (rc < 0) -- GitLab From 68c624f860b30408afde81a91b4c9df3e915ed85 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Mon, 17 Jul 2023 13:40:58 +0100 Subject: [PATCH 0465/3445] rtc: pcf85063: Simplify probe() The pcf85063_ids[].driver_data could store a pointer to the config, like for DT-based matching, making I2C and DT-based matching more similar. After that, we can simplify the probe() by replacing of_device_get_ match_data() and i2c_match_id() by i2c_get_match_data() as we have similar I2C and DT-based matching table. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230717124059.196244-2-biju.das.jz@bp.renesas.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf85063.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index e517abfaee2a0..a3b75c96ff9ae 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -556,8 +556,6 @@ static struct pcf85063_config pcf85063_cfg[] = { }, }; -static const struct i2c_device_id pcf85063_ids[]; - static int pcf85063_probe(struct i2c_client *client) { struct pcf85063 *pcf85063; @@ -579,17 +577,9 @@ static int pcf85063_probe(struct i2c_client *client) if (!pcf85063) return -ENOMEM; - if (client->dev.of_node) { - config = of_device_get_match_data(&client->dev); - if (!config) - return -ENODEV; - } else { - enum pcf85063_type type = - i2c_match_id(pcf85063_ids, client)->driver_data; - if (type >= PCF85063_LAST_ID) - return -ENODEV; - config = &pcf85063_cfg[type]; - } + config = i2c_get_match_data(client); + if (!config) + return -ENODEV; pcf85063->regmap = devm_regmap_init_i2c(client, &config->regmap); if (IS_ERR(pcf85063->regmap)) @@ -655,11 +645,11 @@ static int pcf85063_probe(struct i2c_client *client) } static const struct i2c_device_id pcf85063_ids[] = { - { "pca85073a", PCF85063A }, - { "pcf85063", PCF85063 }, - { "pcf85063tp", PCF85063TP }, - { "pcf85063a", PCF85063A }, - { "rv8263", RV8263 }, + { "pca85073a", .driver_data = (kernel_ulong_t)&pcf85063_cfg[PCF85063A] }, + { "pcf85063", .driver_data = (kernel_ulong_t)&pcf85063_cfg[PCF85063] }, + { "pcf85063tp", .driver_data = (kernel_ulong_t)&pcf85063_cfg[PCF85063TP] }, + { "pcf85063a", .driver_data = (kernel_ulong_t)&pcf85063_cfg[PCF85063A] }, + { "rv8263", .driver_data = (kernel_ulong_t)&pcf85063_cfg[RV8263] }, {} }; MODULE_DEVICE_TABLE(i2c, pcf85063_ids); -- GitLab From 5789837c782771eadc9be47487067399609832e7 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Mon, 17 Jul 2023 13:40:59 +0100 Subject: [PATCH 0466/3445] rtc: pcf85063: Drop enum pcf85063_type and split pcf85063_cfg[] Drop enum pcf85063_type and split the array pcf85063_cfg[] as individual variables, and make lines shorter by referring to e.g. &pcf85063_cfg instead of &pcf85063_cfg[PCF85063]. Suggested-by: Geert Uytterhoeven Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230717124059.196244-3-biju.das.jz@bp.renesas.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf85063.c | 83 +++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 45 deletions(-) diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index a3b75c96ff9ae..f501b6f9ed014 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -514,46 +514,39 @@ static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063) } #endif -enum pcf85063_type { - PCF85063, - PCF85063TP, - PCF85063A, - RV8263, - PCF85063_LAST_ID +static const struct pcf85063_config config_pcf85063 = { + .regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x0a, + }, }; -static struct pcf85063_config pcf85063_cfg[] = { - [PCF85063] = { - .regmap = { - .reg_bits = 8, - .val_bits = 8, - .max_register = 0x0a, - }, - }, - [PCF85063TP] = { - .regmap = { - .reg_bits = 8, - .val_bits = 8, - .max_register = 0x0a, - }, +static const struct pcf85063_config config_pcf85063tp = { + .regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x0a, }, - [PCF85063A] = { - .regmap = { - .reg_bits = 8, - .val_bits = 8, - .max_register = 0x11, - }, - .has_alarms = 1, +}; + +static const struct pcf85063_config config_pcf85063a = { + .regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x11, }, - [RV8263] = { - .regmap = { - .reg_bits = 8, - .val_bits = 8, - .max_register = 0x11, - }, - .has_alarms = 1, - .force_cap_7000 = 1, + .has_alarms = 1, +}; + +static const struct pcf85063_config config_rv8263 = { + .regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x11, }, + .has_alarms = 1, + .force_cap_7000 = 1, }; static int pcf85063_probe(struct i2c_client *client) @@ -645,22 +638,22 @@ static int pcf85063_probe(struct i2c_client *client) } static const struct i2c_device_id pcf85063_ids[] = { - { "pca85073a", .driver_data = (kernel_ulong_t)&pcf85063_cfg[PCF85063A] }, - { "pcf85063", .driver_data = (kernel_ulong_t)&pcf85063_cfg[PCF85063] }, - { "pcf85063tp", .driver_data = (kernel_ulong_t)&pcf85063_cfg[PCF85063TP] }, - { "pcf85063a", .driver_data = (kernel_ulong_t)&pcf85063_cfg[PCF85063A] }, - { "rv8263", .driver_data = (kernel_ulong_t)&pcf85063_cfg[RV8263] }, + { "pca85073a", .driver_data = (kernel_ulong_t)&config_pcf85063a }, + { "pcf85063", .driver_data = (kernel_ulong_t)&config_pcf85063 }, + { "pcf85063tp", .driver_data = (kernel_ulong_t)&config_pcf85063tp }, + { "pcf85063a", .driver_data = (kernel_ulong_t)&config_pcf85063a }, + { "rv8263", .driver_data = (kernel_ulong_t)&config_rv8263 }, {} }; MODULE_DEVICE_TABLE(i2c, pcf85063_ids); #ifdef CONFIG_OF static const struct of_device_id pcf85063_of_match[] = { - { .compatible = "nxp,pca85073a", .data = &pcf85063_cfg[PCF85063A] }, - { .compatible = "nxp,pcf85063", .data = &pcf85063_cfg[PCF85063] }, - { .compatible = "nxp,pcf85063tp", .data = &pcf85063_cfg[PCF85063TP] }, - { .compatible = "nxp,pcf85063a", .data = &pcf85063_cfg[PCF85063A] }, - { .compatible = "microcrystal,rv8263", .data = &pcf85063_cfg[RV8263] }, + { .compatible = "nxp,pca85073a", .data = &config_pcf85063a }, + { .compatible = "nxp,pcf85063", .data = &config_pcf85063 }, + { .compatible = "nxp,pcf85063tp", .data = &config_pcf85063tp }, + { .compatible = "nxp,pcf85063a", .data = &config_pcf85063a }, + { .compatible = "microcrystal,rv8263", .data = &config_rv8263 }, {} }; MODULE_DEVICE_TABLE(of, pcf85063_of_match); -- GitLab From 766c3f8a092b4d42abd68ee0338349838430a5ee Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 19 Jul 2023 21:28:18 +0200 Subject: [PATCH 0467/3445] rtc: bq4802: add sparc dependency The added HAS_IOPORT dependency might not actually be necessary as Geert points out, but the driver is also only used on one architecture. Sparc is also a special case here since it converts port numbers into virtual addresses rather than having them mapped into a particular part of the __iomem address space, so the difference is actually not important here. Add a dependency on sparc, but allow compile-testing otherwise, to make this clearer without anyone having to spend much time modernizing the driver beyond that. Reported-by: Geert Uytterhoeven Cc: David S. Miller Link: https://lore.kernel.org/all/CAMuHMdWEx0F=fNei4Bz_JPkuvoaN-+zk08h0i8KnSi_VjO615g@mail.gmail.com/ Signed-off-by: Arnd Bergmann Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230719192835.1025406-1-arnd@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index e8bad8c93ba99..d7502433c78aa 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1196,6 +1196,7 @@ config RTC_DRV_MSM6242 config RTC_DRV_BQ4802 tristate "TI BQ4802" depends on HAS_IOMEM && HAS_IOPORT + depends on SPARC || COMPILE_TEST help If you say Y here you will get support for the TI BQ4802 RTC chip. -- GitLab From 3c87b351809f220294aec3c0df7b078ff5c5b15b Mon Sep 17 00:00:00 2001 From: Andrej Picej Date: Fri, 23 Jun 2023 10:15:33 +0200 Subject: [PATCH 0468/3445] rtc: rv3028: Add support for "aux-voltage-chargeable" property Property "trickle-resistor-ohms" allows us to set trickle charger resistor. However there is no possibility to disable it afterwards. Add support for "aux-voltage-chargeable" property which can be used to enable/disable the trickle charger circuit explicitly. The default behavior of the code is kept as it is! Additionally, lets make sure we only update internal EEPROM in case of a change. This prevents wear due to excessive EEPROM writes on each probe. Signed-off-by: Andrej Picej Link: https://lore.kernel.org/r/20230623081533.76334-1-andrej.picej@norik.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rv3028.c | 80 ++++++++++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 19 deletions(-) diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c index 076e56f4e01a5..e039b472eaa63 100644 --- a/drivers/rtc/rtc-rv3028.c +++ b/drivers/rtc/rtc-rv3028.c @@ -855,11 +855,68 @@ static const struct regmap_config regmap_config = { .max_register = 0x37, }; +static u8 rv3028_set_trickle_charger(struct rv3028_data *rv3028, + struct i2c_client *client) +{ + int ret, val_old, val; + u32 ohms, chargeable; + + ret = regmap_read(rv3028->regmap, RV3028_BACKUP, &val_old); + if (ret < 0) + return ret; + + /* mask out only trickle charger bits */ + val_old = val_old & (RV3028_BACKUP_TCE | RV3028_BACKUP_TCR_MASK); + val = val_old; + + /* setup trickle charger */ + if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms", + &ohms)) { + int i; + + for (i = 0; i < ARRAY_SIZE(rv3028_trickle_resistors); i++) + if (ohms == rv3028_trickle_resistors[i]) + break; + + if (i < ARRAY_SIZE(rv3028_trickle_resistors)) { + /* enable trickle charger and its resistor */ + val = RV3028_BACKUP_TCE | i; + } else { + dev_warn(&client->dev, "invalid trickle resistor value\n"); + } + } + + if (!device_property_read_u32(&client->dev, "aux-voltage-chargeable", + &chargeable)) { + switch (chargeable) { + case 0: + val &= ~RV3028_BACKUP_TCE; + break; + case 1: + val |= RV3028_BACKUP_TCE; + break; + default: + dev_warn(&client->dev, + "unsupported aux-voltage-chargeable value\n"); + break; + } + } + + /* only update EEPROM if changes are necessary */ + if (val_old != val) { + ret = rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_TCE | + RV3028_BACKUP_TCR_MASK, val); + if (ret) + return ret; + } + + return ret; +} + static int rv3028_probe(struct i2c_client *client) { struct rv3028_data *rv3028; int ret, status; - u32 ohms; struct nvmem_config nvmem_cfg = { .name = "rv3028_nvram", .word_size = 1, @@ -937,24 +994,9 @@ static int rv3028_probe(struct i2c_client *client) if (ret) return ret; - /* setup trickle charger */ - if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms", - &ohms)) { - int i; - - for (i = 0; i < ARRAY_SIZE(rv3028_trickle_resistors); i++) - if (ohms == rv3028_trickle_resistors[i]) - break; - - if (i < ARRAY_SIZE(rv3028_trickle_resistors)) { - ret = rv3028_update_cfg(rv3028, RV3028_BACKUP, RV3028_BACKUP_TCE | - RV3028_BACKUP_TCR_MASK, RV3028_BACKUP_TCE | i); - if (ret) - return ret; - } else { - dev_warn(&client->dev, "invalid trickle resistor value\n"); - } - } + ret = rv3028_set_trickle_charger(rv3028, client); + if (ret) + return ret; ret = rtc_add_group(rv3028->rtc, &rv3028_attr_group); if (ret) -- GitLab From 574ca75f8d2935053872aa1b15d8ba24bfb5e51c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Jul 2023 11:46:23 -0600 Subject: [PATCH 0469/3445] i3c: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Reviewed-by: Jeremy Kerr Link: https://lore.kernel.org/r/20230714174623.4057784-1-robh@kernel.org Signed-off-by: Alexandre Belloni --- drivers/i3c/master/ast2600-i3c-master.c | 1 - drivers/i3c/master/i3c-master-cdns.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/i3c/master/ast2600-i3c-master.c b/drivers/i3c/master/ast2600-i3c-master.c index 09ed19d489e9c..01a47d3dd499f 100644 --- a/drivers/i3c/master/ast2600-i3c-master.c +++ b/drivers/i3c/master/ast2600-i3c-master.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c index 01610fa5b0ccf..49551db71bc96 100644 --- a/drivers/i3c/master/i3c-master-cdns.c +++ b/drivers/i3c/master/i3c-master-cdns.c @@ -22,7 +22,6 @@ #include #include #include -#include #define DEV_ID 0x0 #define DEV_ID_I3C_MASTER 0x5034 -- GitLab From 48144c2890503b919bc8ee128b63e37008d69250 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 24 Jul 2023 14:54:54 -0600 Subject: [PATCH 0470/3445] rtc: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230724205456.767430-1-robh@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-abx80x.c | 2 +- drivers/rtc/rtc-armada38x.c | 1 - drivers/rtc/rtc-at91rm9200.c | 1 - drivers/rtc/rtc-ds1742.c | 1 - drivers/rtc/rtc-fsl-ftm-alarm.c | 5 +---- drivers/rtc/rtc-isl12026.c | 1 - drivers/rtc/rtc-isl1208.c | 2 +- drivers/rtc/rtc-jz4740.c | 2 +- drivers/rtc/rtc-lpc24xx.c | 3 +-- drivers/rtc/rtc-m41t80.c | 2 +- drivers/rtc/rtc-mpc5121.c | 4 +--- drivers/rtc/rtc-mt6397.c | 2 +- drivers/rtc/rtc-mt7622.c | 4 ++-- drivers/rtc/rtc-mxc.c | 1 - drivers/rtc/rtc-pcf85063.c | 2 +- drivers/rtc/rtc-pcf85363.c | 1 - drivers/rtc/rtc-pxa.c | 1 - drivers/rtc/rtc-rs5c372.c | 2 +- drivers/rtc/rtc-rv3028.c | 2 +- drivers/rtc/rtc-rv3032.c | 2 +- drivers/rtc/rtc-rv8803.c | 2 +- drivers/rtc/rtc-rx6110.c | 1 - drivers/rtc/rtc-rx8581.c | 1 - drivers/rtc/rtc-rzn1.c | 2 +- drivers/rtc/rtc-s3c.c | 1 - drivers/rtc/rtc-stm32.c | 3 ++- drivers/rtc/rtc-stmp3xxx.c | 1 - drivers/rtc/rtc-sun6i.c | 1 - drivers/rtc/rtc-sunxi.c | 2 -- drivers/rtc/rtc-ti-k3.c | 2 +- 30 files changed, 19 insertions(+), 38 deletions(-) diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c index e08d3181bd2a6..fde2b8054c2ea 100644 --- a/drivers/rtc/rtc-abx80x.c +++ b/drivers/rtc/rtc-abx80x.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c index b4139c2006766..8abcad38b10c2 100644 --- a/drivers/rtc/rtc-armada38x.c +++ b/drivers/rtc/rtc-armada38x.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index e9d17232d0a81..245588a7b417c 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index a5026b0514e78..6ae8b9a294fee 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/rtc/rtc-fsl-ftm-alarm.c b/drivers/rtc/rtc-fsl-ftm-alarm.c index 3d7c4077fe1c6..a72c4ad0cec6e 100644 --- a/drivers/rtc/rtc-fsl-ftm-alarm.c +++ b/drivers/rtc/rtc-fsl-ftm-alarm.c @@ -11,11 +11,8 @@ #include #include #include -#include -#include #include -#include -#include +#include #include #include #include diff --git a/drivers/rtc/rtc-isl12026.c b/drivers/rtc/rtc-isl12026.c index 5abff5d348acd..8b00659fc955e 100644 --- a/drivers/rtc/rtc-isl12026.c +++ b/drivers/rtc/rtc-isl12026.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index 57e77b55e4842..712ca652d6d3c 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 36453b008139b..6ba889d7d4c4f 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/rtc/rtc-lpc24xx.c b/drivers/rtc/rtc-lpc24xx.c index a4612e543f353..df17c48ff086e 100644 --- a/drivers/rtc/rtc-lpc24xx.c +++ b/drivers/rtc/rtc-lpc24xx.c @@ -9,9 +9,8 @@ #include #include #include +#include #include -#include -#include #include #include diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 3cc5151e09864..866489ad56d67 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index 07df43e4c4d06..28858fcaea8f6 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -11,10 +11,8 @@ #include #include #include -#include -#include #include -#include +#include #include #include diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c index 1d297af80f878..1617063669cc5 100644 --- a/drivers/rtc/rtc-mt6397.c +++ b/drivers/rtc/rtc-mt6397.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/rtc/rtc-mt7622.c b/drivers/rtc/rtc-mt7622.c index 81857a457c326..094c649fc137f 100644 --- a/drivers/rtc/rtc-mt7622.c +++ b/drivers/rtc/rtc-mt7622.c @@ -7,9 +7,9 @@ #include #include +#include +#include #include -#include -#include #include #include diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index 762cf03345f14..dbb935dbbd8ab 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -11,7 +11,6 @@ #include #include #include -#include #define RTC_INPUT_CLK_32768HZ (0x00 << 5) #define RTC_INPUT_CLK_32000HZ (0x01 << 5) diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index f501b6f9ed014..fdbc07f14036a 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/rtc/rtc-pcf85363.c b/drivers/rtc/rtc-pcf85363.c index 65b8b1338dbb0..569c79bac0ee8 100644 --- a/drivers/rtc/rtc-pcf85363.c +++ b/drivers/rtc/rtc-pcf85363.c @@ -15,7 +15,6 @@ #include #include #include -#include #include /* diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index eeacf480cf362..e400c78252e82 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "rtc-sa1100.h" diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index a5a6c8772ecd4..ecabeef091960 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include /* * Ricoh has a family of I2C based RTCs, which differ only slightly from diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c index e039b472eaa63..2f001c59c61d5 100644 --- a/drivers/rtc/rtc-rv3028.c +++ b/drivers/rtc/rtc-rv3028.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c index 6b8eb2039a333..35b2e36b426a0 100644 --- a/drivers/rtc/rtc-rv3032.c +++ b/drivers/rtc/rtc-rv3032.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index 98679cae13e84..fd8ab0b2f731b 100644 --- a/drivers/rtc/rtc-rv8803.c +++ b/drivers/rtc/rtc-rv8803.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #define RV8803_I2C_TRY_COUNT 4 diff --git a/drivers/rtc/rtc-rx6110.c b/drivers/rtc/rtc-rx6110.c index 8702db6096ba4..834274db8c3fd 100644 --- a/drivers/rtc/rtc-rx6110.c +++ b/drivers/rtc/rtc-rx6110.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/rtc/rtc-rx8581.c b/drivers/rtc/rtc-rx8581.c index 82881fd2e14a1..48efd61a114d4 100644 --- a/drivers/rtc/rtc-rx8581.c +++ b/drivers/rtc/rtc-rx8581.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/rtc/rtc-rzn1.c b/drivers/rtc/rtc-rzn1.c index dca736caba852..6f98969eedca3 100644 --- a/drivers/rtc/rtc-rzn1.c +++ b/drivers/rtc/rtc-rzn1.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 70e1a18e5efdf..282238818f63b 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index 85689192fa7ae..3ae875b19af82 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -11,7 +11,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index 6f11b745f34d9..7566d0a44af82 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c index 71548dd59a3a6..753a2d9c8a177 100644 --- a/drivers/rtc/rtc-sun6i.c +++ b/drivers/rtc/rtc-sun6i.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/rtc/rtc-sunxi.c b/drivers/rtc/rtc-sunxi.c index 5d019e3a835ad..5cab9953c44f5 100644 --- a/drivers/rtc/rtc-sunxi.c +++ b/drivers/rtc/rtc-sunxi.c @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/drivers/rtc/rtc-ti-k3.c b/drivers/rtc/rtc-ti-k3.c index 0d90fe9233550..ec759d8f7023c 100644 --- a/drivers/rtc/rtc-ti-k3.c +++ b/drivers/rtc/rtc-ti-k3.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include -- GitLab From 58f3e83260a78cfd5648efa5448b237b9c230fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 25 Jul 2023 09:04:29 +0200 Subject: [PATCH 0471/3445] rtc: isl12026: Drop "_new" from probe callback name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver was introduced when .probe_new was the right probe callback to use for i2c drivers. Today .probe is the right one (again) and the driver was already switched in commit 31b0cecb4042 ("rtc: Switch i2c drivers back to use .probe()") but the name continued to include "_new" in its name. To prevent code readers wondering about what might be new here, drop that irritating part of the name. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230725070429.383070-1-u.kleine-koenig@pengutronix.de Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl12026.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-isl12026.c b/drivers/rtc/rtc-isl12026.c index 8b00659fc955e..2aabb9151d4c6 100644 --- a/drivers/rtc/rtc-isl12026.c +++ b/drivers/rtc/rtc-isl12026.c @@ -428,7 +428,7 @@ static void isl12026_force_power_modes(struct i2c_client *client) } } -static int isl12026_probe_new(struct i2c_client *client) +static int isl12026_probe(struct i2c_client *client) { struct isl12026 *priv; int ret; @@ -489,7 +489,7 @@ static struct i2c_driver isl12026_driver = { .name = "rtc-isl12026", .of_match_table = isl12026_dt_match, }, - .probe = isl12026_probe_new, + .probe = isl12026_probe, .remove = isl12026_remove, }; -- GitLab From 018121e655c8ac2b369f70758dbddf7a37ef534f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 25 Jul 2023 10:19:45 +0200 Subject: [PATCH 0472/3445] pwm: Remove outdated documentation for pwmchip_remove() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pwmchip_remove() returns void since some time but the documentation still mentions the situations where it used to return an error code. Just remove this old and now wrong text. Fixes: 8083f58d08fd ("pwm: Make pwmchip_remove() return void") Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 11f2f1fd08467..00e85acd92c4f 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -313,10 +313,7 @@ EXPORT_SYMBOL_GPL(pwmchip_add); * pwmchip_remove() - remove a PWM chip * @chip: the PWM chip to remove * - * Removes a PWM chip. This function may return busy if the PWM chip provides - * a PWM device that is still requested. - * - * Returns: 0 on success or a negative error code on failure. + * Removes a PWM chip. */ void pwmchip_remove(struct pwm_chip *chip) { -- GitLab From bdebe27e3dc22c11c72b0d1ef4ed30355f154e58 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 25 Jul 2023 14:59:21 +0100 Subject: [PATCH 0473/3445] pwm: rz-mtu3: Fix build warning 'num_channel_ios' not described Fix the below build warning: warning: Function parameter or member 'num_channel_ios' not described in 'rz_mtu3_channel_io_map' Signed-off-by: Biju Das Signed-off-by: Thierry Reding --- drivers/pwm/pwm-rz-mtu3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-rz-mtu3.c b/drivers/pwm/pwm-rz-mtu3.c index bed8bd671e374..a56cecb0e46e3 100644 --- a/drivers/pwm/pwm-rz-mtu3.c +++ b/drivers/pwm/pwm-rz-mtu3.c @@ -40,7 +40,7 @@ * struct rz_mtu3_channel_io_map - MTU3 pwm channel map * * @base_pwm_number: First PWM of a channel - * @num: number of IOs on the HW channel. + * @num_channel_ios: number of IOs on the HW channel. */ struct rz_mtu3_channel_io_map { u8 base_pwm_number; -- GitLab From 84c33f4278249aecb49375fb884b0b14a3664a63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 28 Jul 2023 09:12:59 +0200 Subject: [PATCH 0474/3445] pwm: Drop unused #include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit core.c doens't use any of the symbols provided by linux/radix-tree.h and compiles just fine without this include. So drop the #include. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 00e85acd92c4f..b4703dfc9e4de 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include -- GitLab From 0323e8fedd1ef25342cf7abf3a2024f5670362b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 19 Jul 2023 21:20:09 +0200 Subject: [PATCH 0475/3445] pwm: atmel-tcb: Harmonize resource allocation order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allocate driver data as first resource in the probe function. This way it can be used during allocation of the other resources (instead of assigning these to local variables first and update driver data only when it's allocated). Also as driver data is allocated using a devm function this should happen first to have the order of freeing resources in the error path and the remove function in reverse. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel-tcb.c | 49 +++++++++++++++---------------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c index 563162d660d8e..c20054a683684 100644 --- a/drivers/pwm/pwm-atmel-tcb.c +++ b/drivers/pwm/pwm-atmel-tcb.c @@ -421,13 +421,14 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) struct atmel_tcb_pwm_chip *tcbpwm; const struct atmel_tcb_config *config; struct device_node *np = pdev->dev.of_node; - struct regmap *regmap; - struct clk *clk, *gclk = NULL; - struct clk *slow_clk; char clk_name[] = "t0_clk"; int err; int channel; + tcbpwm = devm_kzalloc(&pdev->dev, sizeof(*tcbpwm), GFP_KERNEL); + if (tcbpwm == NULL) + return -ENOMEM; + err = of_property_read_u32(np, "reg", &channel); if (err < 0) { dev_err(&pdev->dev, @@ -436,47 +437,37 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) return err; } - regmap = syscon_node_to_regmap(np->parent); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); + tcbpwm->regmap = syscon_node_to_regmap(np->parent); + if (IS_ERR(tcbpwm->regmap)) + return PTR_ERR(tcbpwm->regmap); - slow_clk = of_clk_get_by_name(np->parent, "slow_clk"); - if (IS_ERR(slow_clk)) - return PTR_ERR(slow_clk); + tcbpwm->slow_clk = of_clk_get_by_name(np->parent, "slow_clk"); + if (IS_ERR(tcbpwm->slow_clk)) + return PTR_ERR(tcbpwm->slow_clk); clk_name[1] += channel; - clk = of_clk_get_by_name(np->parent, clk_name); - if (IS_ERR(clk)) - clk = of_clk_get_by_name(np->parent, "t0_clk"); - if (IS_ERR(clk)) - return PTR_ERR(clk); + tcbpwm->clk = of_clk_get_by_name(np->parent, clk_name); + if (IS_ERR(tcbpwm->clk)) + tcbpwm->clk = of_clk_get_by_name(np->parent, "t0_clk"); + if (IS_ERR(tcbpwm->clk)) + return PTR_ERR(tcbpwm->clk); match = of_match_node(atmel_tcb_of_match, np->parent); config = match->data; if (config->has_gclk) { - gclk = of_clk_get_by_name(np->parent, "gclk"); - if (IS_ERR(gclk)) - return PTR_ERR(gclk); - } - - tcbpwm = devm_kzalloc(&pdev->dev, sizeof(*tcbpwm), GFP_KERNEL); - if (tcbpwm == NULL) { - err = -ENOMEM; - goto err_slow_clk; + tcbpwm->gclk = of_clk_get_by_name(np->parent, "gclk"); + if (IS_ERR(tcbpwm->gclk)) + return PTR_ERR(tcbpwm->gclk); } tcbpwm->chip.dev = &pdev->dev; tcbpwm->chip.ops = &atmel_tcb_pwm_ops; tcbpwm->chip.npwm = NPWM; tcbpwm->channel = channel; - tcbpwm->regmap = regmap; - tcbpwm->clk = clk; - tcbpwm->gclk = gclk; - tcbpwm->slow_clk = slow_clk; tcbpwm->width = config->counter_width; - err = clk_prepare_enable(slow_clk); + err = clk_prepare_enable(tcbpwm->slow_clk); if (err) goto err_slow_clk; @@ -494,7 +485,7 @@ err_disable_clk: clk_disable_unprepare(tcbpwm->slow_clk); err_slow_clk: - clk_put(slow_clk); + clk_put(tcbpwm->slow_clk); return err; } -- GitLab From c11622324c023415fb69196c5fc3782d2b8cced0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 19 Jul 2023 21:20:10 +0200 Subject: [PATCH 0476/3445] pwm: atmel-tcb: Fix resource freeing in error path and remove MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Several resources were not freed in the error path and the remove function. Add the forgotten items. Fixes: 34cbcd72588f ("pwm: atmel-tcb: Add sama5d2 support") Fixes: 061f8572a31c ("pwm: atmel-tcb: Switch to new binding") Signed-off-by: Uwe Kleine-König Reviewed-by: Claudiu Beznea Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel-tcb.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c index c20054a683684..825dd04b86a7e 100644 --- a/drivers/pwm/pwm-atmel-tcb.c +++ b/drivers/pwm/pwm-atmel-tcb.c @@ -449,16 +449,20 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) tcbpwm->clk = of_clk_get_by_name(np->parent, clk_name); if (IS_ERR(tcbpwm->clk)) tcbpwm->clk = of_clk_get_by_name(np->parent, "t0_clk"); - if (IS_ERR(tcbpwm->clk)) - return PTR_ERR(tcbpwm->clk); + if (IS_ERR(tcbpwm->clk)) { + err = PTR_ERR(tcbpwm->clk); + goto err_slow_clk; + } match = of_match_node(atmel_tcb_of_match, np->parent); config = match->data; if (config->has_gclk) { tcbpwm->gclk = of_clk_get_by_name(np->parent, "gclk"); - if (IS_ERR(tcbpwm->gclk)) - return PTR_ERR(tcbpwm->gclk); + if (IS_ERR(tcbpwm->gclk)) { + err = PTR_ERR(tcbpwm->gclk); + goto err_clk; + } } tcbpwm->chip.dev = &pdev->dev; @@ -469,7 +473,7 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) err = clk_prepare_enable(tcbpwm->slow_clk); if (err) - goto err_slow_clk; + goto err_gclk; spin_lock_init(&tcbpwm->lock); @@ -484,6 +488,12 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) err_disable_clk: clk_disable_unprepare(tcbpwm->slow_clk); +err_gclk: + clk_put(tcbpwm->gclk); + +err_clk: + clk_put(tcbpwm->clk); + err_slow_clk: clk_put(tcbpwm->slow_clk); @@ -497,8 +507,9 @@ static void atmel_tcb_pwm_remove(struct platform_device *pdev) pwmchip_remove(&tcbpwm->chip); clk_disable_unprepare(tcbpwm->slow_clk); - clk_put(tcbpwm->slow_clk); + clk_put(tcbpwm->gclk); clk_put(tcbpwm->clk); + clk_put(tcbpwm->slow_clk); } static const struct of_device_id atmel_tcb_pwm_dt_ids[] = { -- GitLab From 78dca23bd6706dd6a3cdb5c0052f48794b4d2bed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 19 Jul 2023 21:20:11 +0200 Subject: [PATCH 0477/3445] pwm: atmel-tcb: Put per-channel data into driver data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This simplifies the code, reduces the number of memory allocations and pointer dereferences. Signed-off-by: Uwe Kleine-König Reviewed-by: Claudiu Beznea Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel-tcb.c | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c index 825dd04b86a7e..8d0b74b0307c6 100644 --- a/drivers/pwm/pwm-atmel-tcb.c +++ b/drivers/pwm/pwm-atmel-tcb.c @@ -56,7 +56,7 @@ struct atmel_tcb_pwm_chip { struct clk *clk; struct clk *gclk; struct clk *slow_clk; - struct atmel_tcb_pwm_device *pwms[NPWM]; + struct atmel_tcb_pwm_device pwms[NPWM]; struct atmel_tcb_channel bkup; }; @@ -72,7 +72,7 @@ static int atmel_tcb_pwm_set_polarity(struct pwm_chip *chip, enum pwm_polarity polarity) { struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip); - struct atmel_tcb_pwm_device *tcbpwm = tcbpwmc->pwms[pwm->hwpwm]; + struct atmel_tcb_pwm_device *tcbpwm = &tcbpwmc->pwms[pwm->hwpwm]; tcbpwm->polarity = polarity; @@ -83,19 +83,13 @@ static int atmel_tcb_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) { struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip); - struct atmel_tcb_pwm_device *tcbpwm; + struct atmel_tcb_pwm_device *tcbpwm = &tcbpwmc->pwms[pwm->hwpwm]; unsigned cmr; int ret; - tcbpwm = devm_kzalloc(chip->dev, sizeof(*tcbpwm), GFP_KERNEL); - if (!tcbpwm) - return -ENOMEM; - ret = clk_prepare_enable(tcbpwmc->clk); - if (ret) { - devm_kfree(chip->dev, tcbpwm); + if (ret) return ret; - } tcbpwm->polarity = PWM_POLARITY_NORMAL; tcbpwm->duty = 0; @@ -130,25 +124,20 @@ static int atmel_tcb_pwm_request(struct pwm_chip *chip, regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CMR), cmr); spin_unlock(&tcbpwmc->lock); - tcbpwmc->pwms[pwm->hwpwm] = tcbpwm; - return 0; } static void atmel_tcb_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) { struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip); - struct atmel_tcb_pwm_device *tcbpwm = tcbpwmc->pwms[pwm->hwpwm]; clk_disable_unprepare(tcbpwmc->clk); - tcbpwmc->pwms[pwm->hwpwm] = NULL; - devm_kfree(chip->dev, tcbpwm); } static void atmel_tcb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) { struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip); - struct atmel_tcb_pwm_device *tcbpwm = tcbpwmc->pwms[pwm->hwpwm]; + struct atmel_tcb_pwm_device *tcbpwm = &tcbpwmc->pwms[pwm->hwpwm]; unsigned cmr; enum pwm_polarity polarity = tcbpwm->polarity; @@ -205,7 +194,7 @@ static void atmel_tcb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) static int atmel_tcb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) { struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip); - struct atmel_tcb_pwm_device *tcbpwm = tcbpwmc->pwms[pwm->hwpwm]; + struct atmel_tcb_pwm_device *tcbpwm = &tcbpwmc->pwms[pwm->hwpwm]; u32 cmr; enum pwm_polarity polarity = tcbpwm->polarity; @@ -290,7 +279,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns) { struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip); - struct atmel_tcb_pwm_device *tcbpwm = tcbpwmc->pwms[pwm->hwpwm]; + struct atmel_tcb_pwm_device *tcbpwm = &tcbpwmc->pwms[pwm->hwpwm]; struct atmel_tcb_pwm_device *atcbpwm = NULL; int i = 0; int slowclk = 0; @@ -337,9 +326,9 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, period = div_u64(period_ns, min); if (pwm->hwpwm == 0) - atcbpwm = tcbpwmc->pwms[1]; + atcbpwm = &tcbpwmc->pwms[1]; else - atcbpwm = tcbpwmc->pwms[0]; + atcbpwm = &tcbpwmc->pwms[0]; /* * PWM devices provided by the TCB driver are grouped by 2. -- GitLab From 9a6ac822a2153d583b0da95b8693e954b5f4203a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 19 Jul 2023 21:20:12 +0200 Subject: [PATCH 0478/3445] pwm: atmel-tcb: Unroll atmel_tcb_pwm_set_polarity() into only caller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit atmel_tcb_pwm_set_polarity() is only called once and effectively wraps an assignment only. Replace the function call by the respective assignment. Signed-off-by: Uwe Kleine-König Reviewed-by: Claudiu Beznea Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel-tcb.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c index 8d0b74b0307c6..0c220c0a463c0 100644 --- a/drivers/pwm/pwm-atmel-tcb.c +++ b/drivers/pwm/pwm-atmel-tcb.c @@ -67,18 +67,6 @@ static inline struct atmel_tcb_pwm_chip *to_tcb_chip(struct pwm_chip *chip) return container_of(chip, struct atmel_tcb_pwm_chip, chip); } -static int atmel_tcb_pwm_set_polarity(struct pwm_chip *chip, - struct pwm_device *pwm, - enum pwm_polarity polarity) -{ - struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip); - struct atmel_tcb_pwm_device *tcbpwm = &tcbpwmc->pwms[pwm->hwpwm]; - - tcbpwm->polarity = polarity; - - return 0; -} - static int atmel_tcb_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) { @@ -356,11 +344,12 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, static int atmel_tcb_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_state *state) { + struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip); + struct atmel_tcb_pwm_device *tcbpwm = &tcbpwmc->pwms[pwm->hwpwm]; int duty_cycle, period; int ret; - /* This function only sets a flag in driver data */ - atmel_tcb_pwm_set_polarity(chip, pwm, state->polarity); + tcbpwm->polarity = state->polarity; if (!state->enabled) { atmel_tcb_pwm_disable(chip, pwm); -- GitLab From 28a1dadc49e2902d0a7a2e8c699a15f93b1b6f40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 19 Jul 2023 21:20:13 +0200 Subject: [PATCH 0479/3445] pwm: atmel-tcb: Don't track polarity in driver data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit struct atmel_tcb_pwm_device::polarity is only used in atmel_tcb_pwm_enable and atmel_tcb_pwm_disable(). These functions are only called by atmel_tcb_pwm_apply() after the member variable was assigned to state->polarity. So the value assigned in atmel_tcb_pwm_request() is never used and the member can be dropped from struct atmel_tcb_pwm_device. Signed-off-by: Uwe Kleine-König Reviewed-by: Claudiu Beznea Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel-tcb.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c index 0c220c0a463c0..c00dd37c5fbd8 100644 --- a/drivers/pwm/pwm-atmel-tcb.c +++ b/drivers/pwm/pwm-atmel-tcb.c @@ -33,7 +33,6 @@ ATMEL_TC_BEEVT | ATMEL_TC_BSWTRG) struct atmel_tcb_pwm_device { - enum pwm_polarity polarity; /* PWM polarity */ unsigned div; /* PWM clock divider */ unsigned duty; /* PWM duty expressed in clk cycles */ unsigned period; /* PWM period expressed in clk cycles */ @@ -79,7 +78,6 @@ static int atmel_tcb_pwm_request(struct pwm_chip *chip, if (ret) return ret; - tcbpwm->polarity = PWM_POLARITY_NORMAL; tcbpwm->duty = 0; tcbpwm->period = 0; tcbpwm->div = 0; @@ -122,12 +120,12 @@ static void atmel_tcb_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) clk_disable_unprepare(tcbpwmc->clk); } -static void atmel_tcb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +static void atmel_tcb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm, + enum pwm_polarity polarity) { struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip); struct atmel_tcb_pwm_device *tcbpwm = &tcbpwmc->pwms[pwm->hwpwm]; unsigned cmr; - enum pwm_polarity polarity = tcbpwm->polarity; /* * If duty is 0 the timer will be stopped and we have to @@ -179,12 +177,12 @@ static void atmel_tcb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) spin_unlock(&tcbpwmc->lock); } -static int atmel_tcb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +static int atmel_tcb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm, + enum pwm_polarity polarity) { struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip); struct atmel_tcb_pwm_device *tcbpwm = &tcbpwmc->pwms[pwm->hwpwm]; u32 cmr; - enum pwm_polarity polarity = tcbpwm->polarity; /* * If duty is 0 the timer will be stopped and we have to @@ -344,15 +342,11 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, static int atmel_tcb_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_state *state) { - struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip); - struct atmel_tcb_pwm_device *tcbpwm = &tcbpwmc->pwms[pwm->hwpwm]; int duty_cycle, period; int ret; - tcbpwm->polarity = state->polarity; - if (!state->enabled) { - atmel_tcb_pwm_disable(chip, pwm); + atmel_tcb_pwm_disable(chip, pwm, state->polarity); return 0; } @@ -363,7 +357,7 @@ static int atmel_tcb_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, if (ret) return ret; - return atmel_tcb_pwm_enable(chip, pwm); + return atmel_tcb_pwm_enable(chip, pwm, state->polarity); } static const struct pwm_ops atmel_tcb_pwm_ops = { -- GitLab From 4aed0ccd6868e6ec71f0cf26fc755dbd67447072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 18 Jul 2023 16:41:28 +0200 Subject: [PATCH 0480/3445] pwm: lpc18xx-sct: Simplify using devm_clk_get_enabled() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With devm_clk_get_enabled() the call to clk_disable_unprepare() can be dropped from the error path and the remove callback. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-lpc18xx-sct.c | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c index 9ff6311bd4723..7a19a840bca5f 100644 --- a/drivers/pwm/pwm-lpc18xx-sct.c +++ b/drivers/pwm/pwm-lpc18xx-sct.c @@ -367,30 +367,21 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev) if (IS_ERR(lpc18xx_pwm->base)) return PTR_ERR(lpc18xx_pwm->base); - lpc18xx_pwm->pwm_clk = devm_clk_get(&pdev->dev, "pwm"); + lpc18xx_pwm->pwm_clk = devm_clk_get_enabled(&pdev->dev, "pwm"); if (IS_ERR(lpc18xx_pwm->pwm_clk)) return dev_err_probe(&pdev->dev, PTR_ERR(lpc18xx_pwm->pwm_clk), "failed to get pwm clock\n"); - ret = clk_prepare_enable(lpc18xx_pwm->pwm_clk); - if (ret < 0) - return dev_err_probe(&pdev->dev, ret, - "could not prepare or enable pwm clock\n"); - lpc18xx_pwm->clk_rate = clk_get_rate(lpc18xx_pwm->pwm_clk); - if (!lpc18xx_pwm->clk_rate) { - ret = dev_err_probe(&pdev->dev, - -EINVAL, "pwm clock has no frequency\n"); - goto disable_pwmclk; - } + if (!lpc18xx_pwm->clk_rate) + return dev_err_probe(&pdev->dev, + -EINVAL, "pwm clock has no frequency\n"); /* * If clkrate is too fast, the calculations in .apply() might overflow. */ - if (lpc18xx_pwm->clk_rate > NSEC_PER_SEC) { - ret = dev_err_probe(&pdev->dev, -EINVAL, "pwm clock to fast\n"); - goto disable_pwmclk; - } + if (lpc18xx_pwm->clk_rate > NSEC_PER_SEC) + return dev_err_probe(&pdev->dev, -EINVAL, "pwm clock to fast\n"); mutex_init(&lpc18xx_pwm->res_lock); mutex_init(&lpc18xx_pwm->period_lock); @@ -436,18 +427,12 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev) lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL, val); ret = pwmchip_add(&lpc18xx_pwm->chip); - if (ret < 0) { - dev_err_probe(&pdev->dev, ret, "pwmchip_add failed\n"); - goto disable_pwmclk; - } + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "pwmchip_add failed\n"); platform_set_drvdata(pdev, lpc18xx_pwm); return 0; - -disable_pwmclk: - clk_disable_unprepare(lpc18xx_pwm->pwm_clk); - return ret; } static void lpc18xx_pwm_remove(struct platform_device *pdev) @@ -460,8 +445,6 @@ static void lpc18xx_pwm_remove(struct platform_device *pdev) val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_CTRL); lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL, val | LPC18XX_PWM_CTRL_HALT); - - clk_disable_unprepare(lpc18xx_pwm->pwm_clk); } static struct platform_driver lpc18xx_pwm_driver = { -- GitLab From 63808bbb3e226b0160f61723614e612fbf51541c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 18 Jul 2023 17:06:57 +0200 Subject: [PATCH 0481/3445] pwm: pxa: Don't reimplement of_device_get_match_data() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apart from the return type pxa_pwm_get_id_dt() reimplements of_device_get_match_data(). Drop the former and replace the call to it by the latter. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-pxa.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index c8314053bcb02..1e475ed10180e 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -157,13 +157,6 @@ MODULE_DEVICE_TABLE(of, pwm_of_match); #define pwm_of_match NULL #endif -static const struct platform_device_id *pxa_pwm_get_id_dt(struct device *dev) -{ - const struct of_device_id *id = of_match_device(pwm_of_match, dev); - - return id ? id->data : NULL; -} - static int pwm_probe(struct platform_device *pdev) { const struct platform_device_id *id = platform_get_device_id(pdev); @@ -171,7 +164,7 @@ static int pwm_probe(struct platform_device *pdev) int ret = 0; if (IS_ENABLED(CONFIG_OF) && id == NULL) - id = pxa_pwm_get_id_dt(&pdev->dev); + id = of_device_get_match_data(&pdev->dev); if (id == NULL) return -EINVAL; -- GitLab From 250b4ca0c9d611c61e12a8eb2d24e69f9058de2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 18 Jul 2023 17:23:27 +0200 Subject: [PATCH 0482/3445] pwm: ntxec: Drop a write-only variable from driver data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .dev is assigned in .probe() and never read. So it serves no purpose and can be removed. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-ntxec.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/pwm/pwm-ntxec.c b/drivers/pwm/pwm-ntxec.c index ab63b081df531..baf912c5bf0f0 100644 --- a/drivers/pwm/pwm-ntxec.c +++ b/drivers/pwm/pwm-ntxec.c @@ -24,7 +24,6 @@ #include struct ntxec_pwm { - struct device *dev; struct ntxec *ec; struct pwm_chip chip; }; @@ -148,7 +147,6 @@ static int ntxec_pwm_probe(struct platform_device *pdev) return -ENOMEM; priv->ec = ec; - priv->dev = &pdev->dev; chip = &priv->chip; chip->dev = &pdev->dev; -- GitLab From 387c74e5f91d8e6f0c6e49fddd8b0e53118e5def Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 18 Jul 2023 19:53:10 +0200 Subject: [PATCH 0483/3445] pwm: ntxec: Use device_set_of_node_from_dev() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compared to overwriting pdev->dev.of_node directly, this takes care of reference counting. It also prevents that the parent device matches this driver. See commit 9b22c17a3cc5 ("of: Check 'of_node_reused' flag on of_match_device()") for further details. Suggested-by: Rob Herring Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-ntxec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-ntxec.c b/drivers/pwm/pwm-ntxec.c index baf912c5bf0f0..7514ea384ec56 100644 --- a/drivers/pwm/pwm-ntxec.c +++ b/drivers/pwm/pwm-ntxec.c @@ -140,7 +140,7 @@ static int ntxec_pwm_probe(struct platform_device *pdev) struct ntxec_pwm *priv; struct pwm_chip *chip; - pdev->dev.of_node = pdev->dev.parent->of_node; + device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent); priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) -- GitLab From 86eed2a10304a9efe56c2b192b914b377cad260d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 25 Jul 2023 10:10:04 +0200 Subject: [PATCH 0484/3445] pwm: Fix order of freeing resources in pwmchip_remove() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pwmchip_add() calls of_pwmchip_add() only after adding the chip to pwm_chips and releasing pwm_lock. So the proper order in pwmchip_remove() is to call of_pwmchip_remove() before taking the mutex and removing the chip from pwm_chips. This way pwmchip_remove() releases the resources in reverse order compared to pwmchip_add() requesting them. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index b4703dfc9e4de..dc66e3405bf50 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -318,13 +318,13 @@ void pwmchip_remove(struct pwm_chip *chip) { pwmchip_sysfs_unexport(chip); + if (IS_ENABLED(CONFIG_OF)) + of_pwmchip_remove(chip); + mutex_lock(&pwm_lock); list_del_init(&chip->list); - if (IS_ENABLED(CONFIG_OF)) - of_pwmchip_remove(chip); - free_pwms(chip); mutex_unlock(&pwm_lock); -- GitLab From e9c2f69aac05919a4f2bf72a7b53c43ac3f4c410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 13 Jul 2023 17:51:41 +0200 Subject: [PATCH 0485/3445] pwm: stm32: Don't modify HW state in .remove() callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A consumer is expected to disable a PWM before calling pwm_put(). And if they didn't there is hopefully a good reason (or the consumer needs fixing). Also if disabling an enabled PWM was the right thing to do, this should better be done in the framework instead of in each low level driver. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-stm32.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c index 62e397aeb9aa3..687967d3265f4 100644 --- a/drivers/pwm/pwm-stm32.c +++ b/drivers/pwm/pwm-stm32.c @@ -649,10 +649,6 @@ static int stm32_pwm_probe(struct platform_device *pdev) static void stm32_pwm_remove(struct platform_device *pdev) { struct stm32_pwm *priv = platform_get_drvdata(pdev); - unsigned int i; - - for (i = 0; i < priv->chip.npwm; i++) - pwm_disable(&priv->chip.pwms[i]); pwmchip_remove(&priv->chip); } -- GitLab From 8c89fd866ad221af037ef0ec3d60b83d0b859c65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 13 Jul 2023 17:51:42 +0200 Subject: [PATCH 0486/3445] pwm: stm32: Simplify using devm_pwmchip_add() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows to drop the platform_driver's remove function. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-stm32.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c index 687967d3265f4..3d6be7749e231 100644 --- a/drivers/pwm/pwm-stm32.c +++ b/drivers/pwm/pwm-stm32.c @@ -637,7 +637,7 @@ static int stm32_pwm_probe(struct platform_device *pdev) priv->chip.ops = &stm32pwm_ops; priv->chip.npwm = stm32_pwm_detect_channels(priv); - ret = pwmchip_add(&priv->chip); + ret = devm_pwmchip_add(dev, &priv->chip); if (ret < 0) return ret; @@ -646,13 +646,6 @@ static int stm32_pwm_probe(struct platform_device *pdev) return 0; } -static void stm32_pwm_remove(struct platform_device *pdev) -{ - struct stm32_pwm *priv = platform_get_drvdata(pdev); - - pwmchip_remove(&priv->chip); -} - static int __maybe_unused stm32_pwm_suspend(struct device *dev) { struct stm32_pwm *priv = dev_get_drvdata(dev); @@ -697,7 +690,6 @@ MODULE_DEVICE_TABLE(of, stm32_pwm_of_match); static struct platform_driver stm32_pwm_driver = { .probe = stm32_pwm_probe, - .remove_new = stm32_pwm_remove, .driver = { .name = "stm32-pwm", .of_match_table = stm32_pwm_of_match, -- GitLab From b2c71e9f8dd0d023a847f6c38f9a83c0949ec01a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 14 Jul 2023 23:45:18 +0200 Subject: [PATCH 0487/3445] pwm: stmpe: Handle errors when disabling the signal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before the pwm framework implementedatomic updates (with the .apply() callback) the .disable() callback returned void. This is still visible in the stmpe driver which drops errors in the disable path. Improve the driver to forward failures in stmpe_24xx_pwm_disable() to the caller of pwm_apply_state(). Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-stmpe.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/pwm/pwm-stmpe.c b/drivers/pwm/pwm-stmpe.c index 5d4a4762ce0cd..e205405c4828b 100644 --- a/drivers/pwm/pwm-stmpe.c +++ b/drivers/pwm/pwm-stmpe.c @@ -61,8 +61,8 @@ static int stmpe_24xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) return 0; } -static void stmpe_24xx_pwm_disable(struct pwm_chip *chip, - struct pwm_device *pwm) +static int stmpe_24xx_pwm_disable(struct pwm_chip *chip, + struct pwm_device *pwm) { struct stmpe_pwm *stmpe_pwm = to_stmpe_pwm(chip); u8 value; @@ -72,17 +72,16 @@ static void stmpe_24xx_pwm_disable(struct pwm_chip *chip, if (ret < 0) { dev_err(chip->dev, "error reading PWM#%u control\n", pwm->hwpwm); - return; + return ret; } value = ret & ~BIT(pwm->hwpwm); ret = stmpe_reg_write(stmpe_pwm->stmpe, STMPE24XX_PWMCS, value); - if (ret) { + if (ret) dev_err(chip->dev, "error writing PWM#%u control\n", pwm->hwpwm); - return; - } + return ret; } /* STMPE 24xx PWM instructions */ @@ -111,7 +110,9 @@ static int stmpe_24xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, /* Make sure we are disabled */ if (pwm_is_enabled(pwm)) { - stmpe_24xx_pwm_disable(chip, pwm); + ret = stmpe_24xx_pwm_disable(chip, pwm); + if (ret) + return ret; } else { /* Connect the PWM to the pin */ pin = pwm->hwpwm; @@ -269,7 +270,7 @@ static int stmpe_24xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, if (!state->enabled) { if (pwm->state.enabled) - stmpe_24xx_pwm_disable(chip, pwm); + return stmpe_24xx_pwm_disable(chip, pwm); return 0; } -- GitLab From 8b9d91d23c18423d4e4bda735f20b669fb28115f Mon Sep 17 00:00:00 2001 From: Stanislav Jakubek Date: Sun, 18 Jun 2023 16:23:27 +0200 Subject: [PATCH 0488/3445] dt-bindings: pwm: brcm,kona-pwm: convert to YAML MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert Broadcom Kona family PWM controller bindings to DT schema. Change during conversion: - add used, but previously undocumented brcm,bcm11351-pwm compatible Reviewed-by: Krzysztof Kozlowski Signed-off-by: Stanislav Jakubek Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- .../devicetree/bindings/pwm/brcm,kona-pwm.txt | 21 -------- .../bindings/pwm/brcm,kona-pwm.yaml | 51 +++++++++++++++++++ 2 files changed, 51 insertions(+), 21 deletions(-) delete mode 100644 Documentation/devicetree/bindings/pwm/brcm,kona-pwm.txt create mode 100644 Documentation/devicetree/bindings/pwm/brcm,kona-pwm.yaml diff --git a/Documentation/devicetree/bindings/pwm/brcm,kona-pwm.txt b/Documentation/devicetree/bindings/pwm/brcm,kona-pwm.txt deleted file mode 100644 index c42eecfc81ed0..0000000000000 --- a/Documentation/devicetree/bindings/pwm/brcm,kona-pwm.txt +++ /dev/null @@ -1,21 +0,0 @@ -Broadcom Kona PWM controller device tree bindings - -This controller has 6 channels. - -Required Properties : -- compatible: should contain "brcm,kona-pwm" -- reg: physical base address and length of the controller's registers -- clocks: phandle + clock specifier pair for the external clock -- #pwm-cells: Should be 3. See pwm.yaml in this directory for a - description of the cells format. - -Refer to clocks/clock-bindings.txt for generic clock consumer properties. - -Example: - -pwm: pwm@3e01a000 { - compatible = "brcm,bcm11351-pwm", "brcm,kona-pwm"; - reg = <0x3e01a000 0xc4>; - clocks = <&pwm_clk>; - #pwm-cells = <3>; -}; diff --git a/Documentation/devicetree/bindings/pwm/brcm,kona-pwm.yaml b/Documentation/devicetree/bindings/pwm/brcm,kona-pwm.yaml new file mode 100644 index 0000000000000..e86c8053b366a --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/brcm,kona-pwm.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pwm/brcm,kona-pwm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Broadcom Kona family PWM controller + +description: + This controller has 6 channels. + +maintainers: + - Florian Fainelli + +allOf: + - $ref: pwm.yaml# + +properties: + compatible: + items: + - enum: + - brcm,bcm11351-pwm + - const: brcm,kona-pwm + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + '#pwm-cells': + const: 3 + +required: + - compatible + - reg + - clocks + +unevaluatedProperties: false + +examples: + - | + #include + + pwm@3e01a000 { + compatible = "brcm,bcm11351-pwm", "brcm,kona-pwm"; + reg = <0x3e01a000 0xcc>; + clocks = <&slave_ccu BCM281XX_SLAVE_CCU_PWM>; + #pwm-cells = <3>; + }; +... -- GitLab From b22bb0d6a828b4eab579056647d2f362ac116cf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 28 Jul 2023 10:11:05 +0200 Subject: [PATCH 0489/3445] pwm: atmel: Simplify using devm functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For all resources used by the driver there is a devm variant to allocate these. This simplifies the error path in the probe callback and allows to drop the remove callback. While at it also use dev_err_probe() to compact returning an error. With the remove callback gone, there is no user of driver data left, so the call to platform_set_drvdata() can also be dropped. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel.c | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 03c7810416b84..1f73325d1bea0 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -517,15 +517,10 @@ static int atmel_pwm_probe(struct platform_device *pdev) if (IS_ERR(atmel_pwm->base)) return PTR_ERR(atmel_pwm->base); - atmel_pwm->clk = devm_clk_get(&pdev->dev, NULL); + atmel_pwm->clk = devm_clk_get_prepared(&pdev->dev, NULL); if (IS_ERR(atmel_pwm->clk)) - return PTR_ERR(atmel_pwm->clk); - - ret = clk_prepare(atmel_pwm->clk); - if (ret) { - dev_err(&pdev->dev, "failed to prepare PWM clock\n"); - return ret; - } + return dev_err_probe(&pdev->dev, PTR_ERR(atmel_pwm->clk), + "failed to get prepared PWM clock\n"); atmel_pwm->chip.dev = &pdev->dev; atmel_pwm->chip.ops = &atmel_pwm_ops; @@ -533,42 +528,28 @@ static int atmel_pwm_probe(struct platform_device *pdev) ret = atmel_pwm_enable_clk_if_on(atmel_pwm, true); if (ret < 0) - goto unprepare_clk; + return ret; - ret = pwmchip_add(&atmel_pwm->chip); + ret = devm_pwmchip_add(&pdev->dev, &atmel_pwm->chip); if (ret < 0) { - dev_err(&pdev->dev, "failed to add PWM chip %d\n", ret); + dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n"); goto disable_clk; } - platform_set_drvdata(pdev, atmel_pwm); - - return ret; + return 0; disable_clk: atmel_pwm_enable_clk_if_on(atmel_pwm, false); -unprepare_clk: - clk_unprepare(atmel_pwm->clk); return ret; } -static void atmel_pwm_remove(struct platform_device *pdev) -{ - struct atmel_pwm_chip *atmel_pwm = platform_get_drvdata(pdev); - - pwmchip_remove(&atmel_pwm->chip); - - clk_unprepare(atmel_pwm->clk); -} - static struct platform_driver atmel_pwm_driver = { .driver = { .name = "atmel-pwm", .of_match_table = of_match_ptr(atmel_pwm_dt_ids), }, .probe = atmel_pwm_probe, - .remove_new = atmel_pwm_remove, }; module_platform_driver(atmel_pwm_driver); -- GitLab From ad5152b85e8bc7dacb1e6e237553fbe779c938e0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 23 Jun 2023 15:09:40 +0300 Subject: [PATCH 0490/3445] leds: aw200xx: Fix error code in probe() The "ret" variable is zero/success here. Don't return that, return -EINVAL instead. Fixes: 36a87f371b7a ("leds: Add AW20xx driver") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/4d791b69-01c7-4532-818c-63712d3f63e1@moroto.mountain Signed-off-by: Lee Jones --- drivers/leds/leds-aw200xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/leds-aw200xx.c b/drivers/leds/leds-aw200xx.c index 96979b8e09b7d..7b996bc01c469 100644 --- a/drivers/leds/leds-aw200xx.c +++ b/drivers/leds/leds-aw200xx.c @@ -368,7 +368,7 @@ static int aw200xx_probe_fw(struct device *dev, struct aw200xx *chip) if (!chip->display_rows || chip->display_rows > chip->cdef->display_size_rows_max) { - return dev_err_probe(dev, ret, + return dev_err_probe(dev, -EINVAL, "Invalid leds display size %u\n", chip->display_rows); } -- GitLab From 66c5e98bbf7b7b2ba0a095ef25bf55c7230e846e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 23 Jun 2023 17:22:29 +0200 Subject: [PATCH 0491/3445] leds: simatic-ipc-leds-gpio: Restore LEDS_CLASS dependency A recent rework accidentally lost the dependency on LEDS_CLASS, which leads to a link error when LED support is disbled: x86_64-linux-ld: drivers/leds/simple/simatic-ipc-leds.o: in function `simatic_ipc_leds_probe': simatic-ipc-leds.c:(.text+0x10c): undefined reference to `devm_led_classdev_register_ext' Add back the dependency that was there originally. Fixes: a6c80bec3c935 ("leds: simatic-ipc-leds-gpio: Add GPIO version of Siemens driver") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20230623152233.2246285-1-arnd@kernel.org Signed-off-by: Lee Jones --- drivers/leds/simple/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/leds/simple/Kconfig b/drivers/leds/simple/Kconfig index 44fa0f93cb3b3..02443e745ff3b 100644 --- a/drivers/leds/simple/Kconfig +++ b/drivers/leds/simple/Kconfig @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config LEDS_SIEMENS_SIMATIC_IPC tristate "LED driver for Siemens Simatic IPCs" + depends on LEDS_CLASS depends on SIEMENS_SIMATIC_IPC help This option enables support for the LEDs of several Industrial PCs -- GitLab From 07a476e04f3479b4c5e2e027859b496a48836028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 26 Jun 2023 11:02:54 +0200 Subject: [PATCH 0492/3445] leds: aw200xx: Switch back to use struct i2c_driver::probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit struct i2c_driver::probe_new is about to go away. Switch the driver to use the probe callback with the same prototype. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230626090254.556206-1-u.kleine-koenig@pengutronix.de Signed-off-by: Lee Jones --- drivers/leds/leds-aw200xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/leds-aw200xx.c b/drivers/leds/leds-aw200xx.c index 7b996bc01c469..691a743cc9b0f 100644 --- a/drivers/leds/leds-aw200xx.c +++ b/drivers/leds/leds-aw200xx.c @@ -583,7 +583,7 @@ static struct i2c_driver aw200xx_driver = { .name = "aw200xx", .of_match_table = aw200xx_match_table, }, - .probe_new = aw200xx_probe, + .probe = aw200xx_probe, .remove = aw200xx_remove, .id_table = aw200xx_id, }; -- GitLab From 7a72f33b6771d37aafe1d396f8d49e5886e6262e Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 4 Jul 2023 17:47:45 +0800 Subject: [PATCH 0493/3445] leds: ip30: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230704094745.25665-1-frank.li@vivo.com Signed-off-by: Lee Jones --- drivers/leds/leds-ip30.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/leds/leds-ip30.c b/drivers/leds/leds-ip30.c index 1f952bad0fe86..2df24c3033665 100644 --- a/drivers/leds/leds-ip30.c +++ b/drivers/leds/leds-ip30.c @@ -27,22 +27,16 @@ static void ip30led_set(struct led_classdev *led_cdev, static int ip30led_create(struct platform_device *pdev, int num) { - struct resource *res; struct ip30_led *data; - res = platform_get_resource(pdev, IORESOURCE_MEM, num); - if (!res) - return -EBUSY; - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - data->reg = devm_ioremap_resource(&pdev->dev, res); + data->reg = devm_platform_ioremap_resource(pdev, num); if (IS_ERR(data->reg)) return PTR_ERR(data->reg); - switch (num) { case IP30_LED_SYSTEM: data->cdev.name = "white:power"; -- GitLab From 713899c0627c440851a543b36b0ffe36fade2622 Mon Sep 17 00:00:00 2001 From: Astrid Rost Date: Mon, 3 Jul 2023 15:03:12 +0200 Subject: [PATCH 0494/3445] dt-bindings: leds: Read max-brightness from device tree Normally, the maximum brightness is determined by the hardware, and this property is not required. This property is used to set a software limit. It could happen that an LED is made so bright that it gets damaged or causes damage due to restrictions in a specific system, such as mounting conditions. Note that this flag is mainly used for PWM-LEDs, where it is not possible to map brightness to current. Drivers for other controllers should use led-max-microamp. Signed-off-by: Astrid Rost Reviewed-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Acked-by: Jacek Anaszewski Link: https://lore.kernel.org/r/20230703130313.548519-2-astrid.rost@axis.com Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/leds/common.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Documentation/devicetree/bindings/leds/common.yaml b/Documentation/devicetree/bindings/leds/common.yaml index 58b492d002464..1c425eb5bec90 100644 --- a/Documentation/devicetree/bindings/leds/common.yaml +++ b/Documentation/devicetree/bindings/leds/common.yaml @@ -158,6 +158,18 @@ properties: For flash LED controllers with configurable current this property is mandatory for the LEDs in the non-flash modes (e.g. torch or indicator). + max-brightness: + description: + Normally, the maximum brightness is determined by the hardware, and this + property is not required. This property is used to set a software limit. + It could happen that an LED is made so bright that it gets damaged or + causes damage due to restrictions in a specific system, such as mounting + conditions. + Note that this flag is mainly used for PWM-LEDs, where it is not possible + to map brightness to current. Drivers for other controllers should use + led-max-microamp. + $ref: /schemas/types.yaml#definitions/uint32 + panic-indicator: description: This property specifies that the LED should be used, if at all possible, -- GitLab From 7cd7a2995ecde065a486e077deb002426975fa40 Mon Sep 17 00:00:00 2001 From: Astrid Rost Date: Mon, 3 Jul 2023 15:03:13 +0200 Subject: [PATCH 0495/3445] led: led-class: Read max-brightness from devicetree Normally, the maximum brightness is determined by the hardware, and this property is not required. This property is used to set a software limit. It could happen that an LED is made so bright that it gets damaged or causes damage due to restrictions in a specific system, such as mounting conditions. Note that this flag is mainly used for PWM-LEDs, where it is not possible to map brightness to current. Drivers for other controllers should use led-max-microamp. Reviewed-by: Andy Shevchenko Signed-off-by: Astrid Rost Acked-by: Jacek Anaszewski Link: https://lore.kernel.org/r/20230703130313.548519-3-astrid.rost@axis.com Signed-off-by: Lee Jones --- drivers/leds/led-class.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 6dae56b914fe3..4758da2b59cf6 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -457,6 +457,10 @@ int led_classdev_register_ext(struct device *parent, if (fwnode_property_present(init_data->fwnode, "retain-state-shutdown")) led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN; + + fwnode_property_read_u32(init_data->fwnode, + "max-brightness", + &led_cdev->max_brightness); } } else { proposed_name = led_cdev->name; -- GitLab From 51c8be0c58a73ac243515516f349d44090c54e9b Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 4 Jul 2023 22:29:29 +0200 Subject: [PATCH 0496/3445] dt-bindings: leds: bd2606mvv: Fix maximum register value Since the chip can drive up to 6 lines, the maximum register number should be only 5, not 6. Signed-off-by: Marek Vasut Acked-by: Rob Herring Reviewed-by: Andreas Kemnade Link: https://lore.kernel.org/r/20230704202929.91962-1-marex@denx.de Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/leds/rohm,bd2606mvv.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/rohm,bd2606mvv.yaml b/Documentation/devicetree/bindings/leds/rohm,bd2606mvv.yaml index 14700a2e5feaa..44dd91aa239de 100644 --- a/Documentation/devicetree/bindings/leds/rohm,bd2606mvv.yaml +++ b/Documentation/devicetree/bindings/leds/rohm,bd2606mvv.yaml @@ -35,7 +35,7 @@ properties: description: GPIO pin to enable/disable the device. patternProperties: - "^led@[0-6]$": + "^led@[0-5]$": type: object $ref: common.yaml# unevaluatedProperties: false @@ -43,7 +43,7 @@ patternProperties: properties: reg: minimum: 0 - maximum: 6 + maximum: 5 required: - reg -- GitLab From cadb2de2a7fd9e955381307de3eddfcc386c208e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 11 Jul 2023 09:13:34 +0300 Subject: [PATCH 0497/3445] leds: pwm: Fix error code in led_pwm_create_fwnode() Negative -EINVAL was intended, not positive EINVAL. Fix it. Fixes: 95138e01275e ("leds: pwm: Make error handling more robust") Signed-off-by: Dan Carpenter Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/a33b981a-b2c4-4dc2-b00a-626a090d2f11@moroto.mountain Signed-off-by: Lee Jones --- drivers/leds/leds-pwm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index 29194cc382afb..87c199242f3c8 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -146,7 +146,7 @@ static int led_pwm_create_fwnode(struct device *dev, struct led_pwm_priv *priv) led.name = to_of_node(fwnode)->name; if (!led.name) { - ret = EINVAL; + ret = -EINVAL; goto err_child_out; } -- GitLab From 07cdd959d62ee87eb29aa9a40b2e41bb11ecf4ec Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Thu, 6 Jul 2023 18:10:40 +0200 Subject: [PATCH 0498/3445] leds: simatic-ipc-leds-gpio: Fix comment style in SPDX header This was found with giving the file to checkpatch. Signed-off-by: Henning Schild Link: https://lore.kernel.org/r/20230706161040.21152-3-henning.schild@siemens.com Signed-off-by: Lee Jones --- drivers/leds/simple/simatic-ipc-leds-gpio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/simple/simatic-ipc-leds-gpio.h b/drivers/leds/simple/simatic-ipc-leds-gpio.h index bf258c32f83de..3d4877aa4e0cb 100644 --- a/drivers/leds/simple/simatic-ipc-leds-gpio.h +++ b/drivers/leds/simple/simatic-ipc-leds-gpio.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Siemens SIMATIC IPC driver for GPIO based LEDs * -- GitLab From a4789089b7dea561c2750710065edb8df441648a Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 13 Jul 2023 18:35:15 +0200 Subject: [PATCH 0499/3445] dt-bindings: leds: pca995x: Add binding document for PCA995X chips The PCA995x chips are I2C controlled LED drivers. Each chip has up to 16 outputs, each one with an individual 8-bit resolution PWM for brightness control. Add binding document. Signed-off-by: Marek Vasut Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230713163516.21644-1-marex@denx.de Signed-off-by: Lee Jones --- .../devicetree/bindings/leds/nxp,pca995x.yaml | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/nxp,pca995x.yaml diff --git a/Documentation/devicetree/bindings/leds/nxp,pca995x.yaml b/Documentation/devicetree/bindings/leds/nxp,pca995x.yaml new file mode 100644 index 0000000000000..654915c1f687f --- /dev/null +++ b/Documentation/devicetree/bindings/leds/nxp,pca995x.yaml @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/nxp,pca995x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP PCA995x LED controllers + +maintainers: + - Isai Gaspar + - Marek Vasut + +description: + The NXP PCA9952/PCA9955B are programmable LED controllers connected via I2C + that can drive 16 separate lines. Each of them can be individually switched + on and off, and brightness can be controlled via individual PWM. + + Datasheets are available at + https://www.nxp.com/docs/en/data-sheet/PCA9952_PCA9955.pdf + https://www.nxp.com/docs/en/data-sheet/PCA9955B.pdf + +properties: + compatible: + enum: + - nxp,pca9952 + - nxp,pca9955b + + reg: + maxItems: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^led@[0-9a-f]+$": + type: object + $ref: common.yaml# + unevaluatedProperties: false + + properties: + reg: + minimum: 0 + maximum: 15 + + required: + - reg + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + led-controller@1 { + compatible = "nxp,pca9955b"; + reg = <0x01>; + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0x0>; + color = ; + function = LED_FUNCTION_POWER; + }; + + led@2 { + reg = <0x2>; + color = ; + function = LED_FUNCTION_STATUS; + }; + }; + }; + +... -- GitLab From ee4e80b2962e98faf69afa6230cb0c249fedec9c Mon Sep 17 00:00:00 2001 From: Isai Gaspar Date: Thu, 13 Jul 2023 18:35:16 +0200 Subject: [PATCH 0500/3445] leds: pca995x: Add support for PCA995X chips The PCA995x chips are I2C controlled LED drivers. Each chip has up to 16 outputs, each one with an individual 8-bit resolution PWM for brightness control. Signed-off-by: Isai Gaspar Signed-off-by: Marek Vasut # Basically rewrite the driver Link: https://lore.kernel.org/r/20230713163516.21644-2-marex@denx.de Signed-off-by: Lee Jones --- drivers/leds/Kconfig | 9 ++ drivers/leds/Makefile | 1 + drivers/leds/leds-pca995x.c | 204 ++++++++++++++++++++++++++++++++++++ 3 files changed, 214 insertions(+) create mode 100644 drivers/leds/leds-pca995x.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 6046dfeca16fc..b92208eccdea9 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -521,6 +521,15 @@ config LEDS_PCA963X LED driver chip accessed via the I2C bus. Supported devices include PCA9633 and PCA9634 +config LEDS_PCA995X + tristate "LED Support for PCA995x I2C chips" + depends on LEDS_CLASS + depends on I2C + help + This option enables support for LEDs connected to PCA995x + LED driver chips accessed via the I2C bus. Supported + devices include PCA9955BTW, PCA9952TW and PCA9955TW. + config LEDS_WM831X_STATUS tristate "LED support for status LEDs on WM831x PMICs" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index d71f1226540c2..d7348e8bc019a 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -72,6 +72,7 @@ obj-$(CONFIG_LEDS_OT200) += leds-ot200.o obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o obj-$(CONFIG_LEDS_PCA963X) += leds-pca963x.o +obj-$(CONFIG_LEDS_PCA995X) += leds-pca995x.o obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o obj-$(CONFIG_LEDS_POWERNV) += leds-powernv.o obj-$(CONFIG_LEDS_PWM) += leds-pwm.o diff --git a/drivers/leds/leds-pca995x.c b/drivers/leds/leds-pca995x.c new file mode 100644 index 0000000000000..3ac99a433fcd2 --- /dev/null +++ b/drivers/leds/leds-pca995x.c @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * LED driver for PCA995x I2C LED drivers + * + * Copyright 2011 bct electronic GmbH + * Copyright 2013 Qtechnology/AS + * Copyright 2022 NXP + * Copyright 2023 Marek Vasut + */ + +#include +#include +#include +#include +#include +#include + +/* Register definition */ +#define PCA995X_MODE1 0x00 +#define PCA995X_MODE2 0x01 +#define PCA995X_LEDOUT0 0x02 +#define PCA9955B_PWM0 0x08 +#define PCA9952_PWM0 0x0A +#define PCA9952_IREFALL 0x43 +#define PCA9955B_IREFALL 0x45 + +/* Auto-increment disabled. Normal mode */ +#define PCA995X_MODE1_CFG 0x00 + +/* LED select registers determine the source that drives LED outputs */ +#define PCA995X_LED_OFF 0x0 +#define PCA995X_LED_ON 0x1 +#define PCA995X_LED_PWM_MODE 0x2 +#define PCA995X_LDRX_MASK 0x3 +#define PCA995X_LDRX_BITS 2 + +#define PCA995X_MAX_OUTPUTS 16 +#define PCA995X_OUTPUTS_PER_REG 4 + +#define PCA995X_IREFALL_FULL_CFG 0xFF +#define PCA995X_IREFALL_HALF_CFG (PCA995X_IREFALL_FULL_CFG / 2) + +#define PCA995X_TYPE_NON_B 0 +#define PCA995X_TYPE_B 1 + +#define ldev_to_led(c) container_of(c, struct pca995x_led, ldev) + +struct pca995x_led { + unsigned int led_no; + struct led_classdev ldev; + struct pca995x_chip *chip; +}; + +struct pca995x_chip { + struct regmap *regmap; + struct pca995x_led leds[PCA995X_MAX_OUTPUTS]; + int btype; +}; + +static int pca995x_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct pca995x_led *led = ldev_to_led(led_cdev); + struct pca995x_chip *chip = led->chip; + u8 ledout_addr, pwmout_addr; + int shift, ret; + + pwmout_addr = (chip->btype ? PCA9955B_PWM0 : PCA9952_PWM0) + led->led_no; + ledout_addr = PCA995X_LEDOUT0 + (led->led_no / PCA995X_OUTPUTS_PER_REG); + shift = PCA995X_LDRX_BITS * (led->led_no % PCA995X_OUTPUTS_PER_REG); + + switch (brightness) { + case LED_FULL: + return regmap_update_bits(chip->regmap, ledout_addr, + PCA995X_LDRX_MASK << shift, + PCA995X_LED_ON << shift); + case LED_OFF: + return regmap_update_bits(chip->regmap, ledout_addr, + PCA995X_LDRX_MASK << shift, 0); + default: + /* Adjust brightness as per user input by changing individual PWM */ + ret = regmap_write(chip->regmap, pwmout_addr, brightness); + if (ret) + return ret; + + /* + * Change LDRx configuration to individual brightness via PWM. + * LED will stop blinking if it's doing so. + */ + return regmap_update_bits(chip->regmap, ledout_addr, + PCA995X_LDRX_MASK << shift, + PCA995X_LED_PWM_MODE << shift); + } +} + +static const struct regmap_config pca995x_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x49, +}; + +static int pca995x_probe(struct i2c_client *client) +{ + struct fwnode_handle *led_fwnodes[PCA995X_MAX_OUTPUTS] = { 0 }; + struct fwnode_handle *np, *child; + struct device *dev = &client->dev; + struct pca995x_chip *chip; + struct pca995x_led *led; + int i, btype, reg, ret; + + btype = (unsigned long)device_get_match_data(&client->dev); + + np = dev_fwnode(dev); + if (!np) + return -ENODEV; + + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->btype = btype; + chip->regmap = devm_regmap_init_i2c(client, &pca995x_regmap); + if (IS_ERR(chip->regmap)) + return PTR_ERR(chip->regmap); + + i2c_set_clientdata(client, chip); + + fwnode_for_each_available_child_node(np, child) { + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret) { + fwnode_handle_put(child); + return ret; + } + + if (reg < 0 || reg >= PCA995X_MAX_OUTPUTS || led_fwnodes[reg]) { + fwnode_handle_put(child); + return -EINVAL; + } + + led = &chip->leds[reg]; + led_fwnodes[reg] = child; + led->chip = chip; + led->led_no = reg; + led->ldev.brightness_set_blocking = pca995x_brightness_set; + led->ldev.max_brightness = 255; + } + + for (i = 0; i < PCA995X_MAX_OUTPUTS; i++) { + struct led_init_data init_data = {}; + + if (!led_fwnodes[i]) + continue; + + init_data.fwnode = led_fwnodes[i]; + + ret = devm_led_classdev_register_ext(dev, + &chip->leds[i].ldev, + &init_data); + if (ret < 0) { + fwnode_handle_put(child); + return dev_err_probe(dev, ret, + "Could not register LED %s\n", + chip->leds[i].ldev.name); + } + } + + /* Disable LED all-call address and set normal mode */ + ret = regmap_write(chip->regmap, PCA995X_MODE1, PCA995X_MODE1_CFG); + if (ret) + return ret; + + /* IREF Output current value for all LEDn outputs */ + return regmap_write(chip->regmap, + btype ? PCA9955B_IREFALL : PCA9952_IREFALL, + PCA995X_IREFALL_HALF_CFG); +} + +static const struct i2c_device_id pca995x_id[] = { + { "pca9952", .driver_data = (kernel_ulong_t)PCA995X_TYPE_NON_B }, + { "pca9955b", .driver_data = (kernel_ulong_t)PCA995X_TYPE_B }, + {} +}; +MODULE_DEVICE_TABLE(i2c, pca995x_id); + +static const struct of_device_id pca995x_of_match[] = { + { .compatible = "nxp,pca9952", .data = (void *)PCA995X_TYPE_NON_B }, + { .compatible = "nxp,pca9955b", .data = (void *)PCA995X_TYPE_B }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, pca995x_of_match); + +static struct i2c_driver pca995x_driver = { + .driver = { + .name = "leds-pca995x", + .of_match_table = pca995x_of_match, + }, + .probe = pca995x_probe, + .id_table = pca995x_id, +}; +module_i2c_driver(pca995x_driver); + +MODULE_AUTHOR("Isai Gaspar "); +MODULE_DESCRIPTION("PCA995x LED driver"); +MODULE_LICENSE("GPL"); -- GitLab From 1ba11daef0a9b062e40b5393d285c82ab6483730 Mon Sep 17 00:00:00 2001 From: Shaoqin Huang Date: Thu, 27 Jul 2023 05:07:54 -0400 Subject: [PATCH 0501/3445] KVM: arm64: Use the known cpu id instead of smp_processor_id() In kvm_arch_vcpu_load(), it has the parameter cpu which is the value of smp_processor_id(), so no need to get it again. Simply replace it. Signed-off-by: Shaoqin Huang Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20230727090754.1900310-1-shahuang@redhat.com --- arch/arm64/kvm/arm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 72dc53a75d1c8..3c015bdd35ee8 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -462,7 +462,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) vcpu_ptrauth_disable(vcpu); kvm_arch_vcpu_load_debug_state_flags(vcpu); - if (!cpumask_test_cpu(smp_processor_id(), vcpu->kvm->arch.supported_cpus)) + if (!cpumask_test_cpu(cpu, vcpu->kvm->arch.supported_cpus)) vcpu_set_on_unsupported_cpu(vcpu); } -- GitLab From e21f3905f98ff1f72b06614440c2be93fda58b44 Mon Sep 17 00:00:00 2001 From: Zenghui Yu Date: Mon, 24 Jul 2023 22:22:57 +0800 Subject: [PATCH 0502/3445] KVM: arm64: Drop HCR_VIRT_EXCP_MASK This was introduced in commit 0369f6a34b9f ("arm64: KVM: EL2 register definitions") and for more than 10 years nobody used. Remove it. Signed-off-by: Zenghui Yu Reviewed-by: Oliver Upton Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20230724142257.1551-1-yuzenghui@huawei.com --- arch/arm64/include/asm/kvm_arm.h | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index 58e5eb27da68d..d04ef89ca6a0a 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -89,7 +89,6 @@ HCR_BSU_IS | HCR_FB | HCR_TACR | \ HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW | HCR_TLOR | \ HCR_FMO | HCR_IMO | HCR_PTW | HCR_TID3) -#define HCR_VIRT_EXCP_MASK (HCR_VSE | HCR_VI | HCR_VF) #define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK | HCR_ATA) #define HCR_HOST_NVHE_PROTECTED_FLAGS (HCR_HOST_NVHE_FLAGS | HCR_TSC) #define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H) -- GitLab From 7e6d86e99a5dee6f81e39f1f6d57091503dc7593 Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Thu, 13 Jul 2023 13:56:39 +0200 Subject: [PATCH 0503/3445] leds: simatic-ipc-leds-gpio: Add Elkhart Lake version This is used for the Siemens Simatic IPC BX-21A, which has its LEDs connected to GPIOs provided by the Intel Elkhart Lake pinctrl driver. Signed-off-by: Henning Schild Link: https://lore.kernel.org/r/20230713115639.16419-3-henning.schild@siemens.com Signed-off-by: Lee Jones --- drivers/leds/simple/Kconfig | 13 +++++ drivers/leds/simple/Makefile | 1 + .../leds/simple/simatic-ipc-leds-gpio-core.c | 4 ++ .../simatic-ipc-leds-gpio-elkhartlake.c | 57 +++++++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 drivers/leds/simple/simatic-ipc-leds-gpio-elkhartlake.c diff --git a/drivers/leds/simple/Kconfig b/drivers/leds/simple/Kconfig index 02443e745ff3b..4496373bfe243 100644 --- a/drivers/leds/simple/Kconfig +++ b/drivers/leds/simple/Kconfig @@ -35,3 +35,16 @@ config LEDS_SIEMENS_SIMATIC_IPC_F7188X To compile this driver as a module, choose M here: the module will be called simatic-ipc-leds-gpio-f7188x. + +config LEDS_SIEMENS_SIMATIC_IPC_ELKHARTLAKE + tristate "LED driver for Siemens Simatic IPCs based on Intel Elkhart Lake GPIO" + depends on LEDS_GPIO + depends on PINCTRL_ELKHARTLAKE + depends on SIEMENS_SIMATIC_IPC + default LEDS_SIEMENS_SIMATIC_IPC + help + This option enables support for the LEDs of several Industrial PCs + from Siemens based on Elkhart Lake GPIO i.e. BX-21A. + + To compile this driver as a module, choose M here: the module + will be called simatic-ipc-leds-gpio-elkhartlake. diff --git a/drivers/leds/simple/Makefile b/drivers/leds/simple/Makefile index e3e840cea275c..783578f11bb0a 100644 --- a/drivers/leds/simple/Makefile +++ b/drivers/leds/simple/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC) += simatic-ipc-leds.o obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC_APOLLOLAKE) += simatic-ipc-leds-gpio-core.o simatic-ipc-leds-gpio-apollolake.o obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC_F7188X) += simatic-ipc-leds-gpio-core.o simatic-ipc-leds-gpio-f7188x.o +obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC_ELKHARTLAKE) += simatic-ipc-leds-gpio-core.o simatic-ipc-leds-gpio-elkhartlake.o diff --git a/drivers/leds/simple/simatic-ipc-leds-gpio-core.c b/drivers/leds/simple/simatic-ipc-leds-gpio-core.c index 2a21b663df874..c552ea73ed9df 100644 --- a/drivers/leds/simple/simatic-ipc-leds-gpio-core.c +++ b/drivers/leds/simple/simatic-ipc-leds-gpio-core.c @@ -57,6 +57,7 @@ int simatic_ipc_leds_gpio_probe(struct platform_device *pdev, switch (plat->devmode) { case SIMATIC_IPC_DEVICE_127E: case SIMATIC_IPC_DEVICE_227G: + case SIMATIC_IPC_DEVICE_BX_21A: break; default: return -ENODEV; @@ -72,6 +73,9 @@ int simatic_ipc_leds_gpio_probe(struct platform_device *pdev, goto out; } + if (!table_extra) + return 0; + table_extra->dev_id = dev_name(dev); gpiod_add_lookup_table(table_extra); diff --git a/drivers/leds/simple/simatic-ipc-leds-gpio-elkhartlake.c b/drivers/leds/simple/simatic-ipc-leds-gpio-elkhartlake.c new file mode 100644 index 0000000000000..6ba21dbb3ba0a --- /dev/null +++ b/drivers/leds/simple/simatic-ipc-leds-gpio-elkhartlake.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Siemens SIMATIC IPC driver for GPIO based LEDs + * + * Copyright (c) Siemens AG, 2023 + * + * Author: + * Henning Schild + */ + +#include +#include +#include +#include +#include +#include + +#include "simatic-ipc-leds-gpio.h" + +static struct gpiod_lookup_table simatic_ipc_led_gpio_table = { + .dev_id = "leds-gpio", + .table = { + GPIO_LOOKUP_IDX("INTC1020:04", 72, NULL, 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("INTC1020:04", 77, NULL, 1, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("INTC1020:04", 78, NULL, 2, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("INTC1020:04", 58, NULL, 3, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("INTC1020:04", 60, NULL, 4, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("INTC1020:04", 62, NULL, 5, GPIO_ACTIVE_HIGH), + {} /* Terminating entry */ + }, +}; + +static int simatic_ipc_leds_gpio_elkhartlake_probe(struct platform_device *pdev) +{ + return simatic_ipc_leds_gpio_probe(pdev, &simatic_ipc_led_gpio_table, + NULL); +} + +static int simatic_ipc_leds_gpio_elkhartlake_remove(struct platform_device *pdev) +{ + return simatic_ipc_leds_gpio_remove(pdev, &simatic_ipc_led_gpio_table, + NULL); +} + +static struct platform_driver simatic_ipc_led_gpio_elkhartlake_driver = { + .probe = simatic_ipc_leds_gpio_elkhartlake_probe, + .remove = simatic_ipc_leds_gpio_elkhartlake_remove, + .driver = { + .name = KBUILD_MODNAME, + }, +}; +module_platform_driver(simatic_ipc_led_gpio_elkhartlake_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" KBUILD_MODNAME); +MODULE_SOFTDEP("pre: simatic-ipc-leds-gpio-core platform:elkhartlake-pinctrl"); +MODULE_AUTHOR("Henning Schild "); -- GitLab From 3c19c79146e1522f52918a5d335523e48f669a1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 14 Jul 2023 08:32:14 +0200 Subject: [PATCH 0504/3445] leds: bcm63138: Rename dependency symbol ARCH_BCM4908 to ARCH_BCMBCA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Symbol ARCH_BCM4908 has been merged/removed without updating leds Kconfig. Fixes: dd5c672d7ca9 ("arm64: bcmbca: Merge ARCH_BCM4908 to ARCH_BCMBCA") Signed-off-by: Rafał Miłecki Reviewed-by: William Zhang Link: https://lore.kernel.org/r/20230714063214.3791-1-zajec5@gmail.com Signed-off-by: Lee Jones --- drivers/leds/blink/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/leds/blink/Kconfig b/drivers/leds/blink/Kconfig index 945c84286a4ed..bdcb7377cd4e0 100644 --- a/drivers/leds/blink/Kconfig +++ b/drivers/leds/blink/Kconfig @@ -1,10 +1,10 @@ config LEDS_BCM63138 tristate "LED Support for Broadcom BCM63138 SoC" depends on LEDS_CLASS - depends on ARCH_BCM4908 || ARCH_BCM_5301X || BCM63XX || COMPILE_TEST + depends on ARCH_BCMBCA || ARCH_BCM_5301X || BCM63XX || COMPILE_TEST depends on HAS_IOMEM depends on OF - default ARCH_BCM4908 + default ARCH_BCMBCA help This option enables support for LED controller that is part of BCM63138 SoC. The same hardware block is known to be also used -- GitLab From 1bb5187b673208f7191f227249ffe7401e969b97 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Jul 2023 11:50:29 -0600 Subject: [PATCH 0505/3445] backlight: qcom-wled: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230714175029.4065326-1-robh@kernel.org Signed-off-by: Lee Jones --- drivers/video/backlight/qcom-wled.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index c6996aa288e62..10129095a4c17 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -9,8 +9,8 @@ #include #include #include -#include #include +#include #include /* From DT binding */ -- GitLab From 3192f141240336dd6d7675ff374757006fed1916 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Jul 2023 11:46:50 -0600 Subject: [PATCH 0506/3445] leds: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230714174651.4058753-1-robh@kernel.org Signed-off-by: Lee Jones --- drivers/leds/leds-ariel.c | 2 +- drivers/leds/leds-cpcap.c | 2 +- drivers/leds/leds-cr0014114.c | 2 +- drivers/leds/leds-is31fl32xx.c | 1 - drivers/leds/leds-mlxreg.c | 1 - drivers/leds/leds-pca9532.c | 1 - drivers/leds/leds-pm8058.c | 1 - drivers/leds/leds-pwm.c | 2 +- drivers/leds/leds-spi-byte.c | 2 +- drivers/leds/leds-syscon.c | 3 +-- drivers/leds/leds-ti-lmu-common.c | 2 +- drivers/leds/leds-tlc591xx.c | 1 - drivers/leds/rgb/leds-qcom-lpg.c | 1 - 13 files changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/leds/leds-ariel.c b/drivers/leds/leds-ariel.c index 49e1bddaa15e0..dd319c7e385fc 100644 --- a/drivers/leds/leds-ariel.c +++ b/drivers/leds/leds-ariel.c @@ -7,8 +7,8 @@ #include #include +#include #include -#include enum ec_index { EC_BLUE_LED = 0x01, diff --git a/drivers/leds/leds-cpcap.c b/drivers/leds/leds-cpcap.c index 7d41ce8c9bb1e..87354f17644ba 100644 --- a/drivers/leds/leds-cpcap.c +++ b/drivers/leds/leds-cpcap.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c index c87686bd7c189..b33bca397ea60 100644 --- a/drivers/leds/leds-cr0014114.c +++ b/drivers/leds/leds-cr0014114.c @@ -4,8 +4,8 @@ #include #include +#include #include -#include #include #include diff --git a/drivers/leds/leds-is31fl32xx.c b/drivers/leds/leds-is31fl32xx.c index 72cb56d305c43..b0a0be77bb33b 100644 --- a/drivers/leds/leds-is31fl32xx.c +++ b/drivers/leds/leds-is31fl32xx.c @@ -15,7 +15,6 @@ #include #include #include -#include /* Used to indicate a device has no such register */ #define IS31FL32XX_REG_NONE 0xFF diff --git a/drivers/leds/leds-mlxreg.c b/drivers/leds/leds-mlxreg.c index b7855c93bd725..39210653acf7f 100644 --- a/drivers/leds/leds-mlxreg.c +++ b/drivers/leds/leds-mlxreg.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index 8b5c62083e508..bf8bb8fc007c6 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c @@ -18,7 +18,6 @@ #include #include #include -#include /* m = num_leds*/ #define PCA9532_REG_INPUT(i) ((i) >> 3) diff --git a/drivers/leds/leds-pm8058.c b/drivers/leds/leds-pm8058.c index b9233f14b6467..3f49a51818925 100644 --- a/drivers/leds/leds-pm8058.c +++ b/drivers/leds/leds-pm8058.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index 87c199242f3c8..419b710984ab6 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/leds/leds-spi-byte.c b/drivers/leds/leds-spi-byte.c index 2c7ffc3c78e66..9d91f21842f2b 100644 --- a/drivers/leds/leds-spi-byte.c +++ b/drivers/leds/leds-spi-byte.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/leds/leds-syscon.c b/drivers/leds/leds-syscon.c index e38abb5e60c1b..360a376fa738c 100644 --- a/drivers/leds/leds-syscon.c +++ b/drivers/leds/leds-syscon.c @@ -7,8 +7,7 @@ */ #include #include -#include -#include +#include #include #include #include diff --git a/drivers/leds/leds-ti-lmu-common.c b/drivers/leds/leds-ti-lmu-common.c index d7f10ad721bad..b2491666b5dc9 100644 --- a/drivers/leds/leds-ti-lmu-common.c +++ b/drivers/leds/leds-ti-lmu-common.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include diff --git a/drivers/leds/leds-tlc591xx.c b/drivers/leds/leds-tlc591xx.c index dfc6fb2b3e522..945e831ef4ac4 100644 --- a/drivers/leds/leds-tlc591xx.c +++ b/drivers/leds/leds-tlc591xx.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c index 59581b3e25ca9..fd7676aa243d5 100644 --- a/drivers/leds/rgb/leds-qcom-lpg.c +++ b/drivers/leds/rgb/leds-qcom-lpg.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include -- GitLab From 4c09e20b3c85f60353ace21092e34f35f5e3ab00 Mon Sep 17 00:00:00 2001 From: Artur Weber Date: Fri, 14 Jul 2023 14:14:39 +0200 Subject: [PATCH 0507/3445] backlight: lp855x: Initialize PWM state on first brightness change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As pointed out by Uwe Kleine-König[1], the changes introduced in commit c1ff7da03e16 ("video: backlight: lp855x: Get PWM for PWM mode during probe") caused the PWM state set up by the bootloader to be re-set when the driver is probed. This differs from the behavior from before that patch, where the PWM state would be initialized on the first brightness change. Fix this by moving the PWM state initialization into the PWM control function. Add a new variable, needs_pwm_init, to the device info struct to allow us to check whether we need the initialization, or whether it has already been done. [1] https://lore.kernel.org/lkml/20230614083953.e4kkweddjz7wztby@pengutronix.de/ Fixes: c1ff7da03e16 ("video: backlight: lp855x: Get PWM for PWM mode during probe") Signed-off-by: Artur Weber Reviewed-by: Daniel Thompson Link: https://lore.kernel.org/r/20230714121440.7717-2-aweber.kernel@gmail.com Signed-off-by: Lee Jones --- drivers/video/backlight/lp855x_bl.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c index 1c9e921bca14a..349ec324bc1ea 100644 --- a/drivers/video/backlight/lp855x_bl.c +++ b/drivers/video/backlight/lp855x_bl.c @@ -71,6 +71,7 @@ struct lp855x { struct device *dev; struct lp855x_platform_data *pdata; struct pwm_device *pwm; + bool needs_pwm_init; struct regulator *supply; /* regulator for VDD input */ struct regulator *enable; /* regulator for EN/VDDIO input */ }; @@ -220,7 +221,15 @@ static void lp855x_pwm_ctrl(struct lp855x *lp, int br, int max_br) { struct pwm_state state; - pwm_get_state(lp->pwm, &state); + if (lp->needs_pwm_init) { + pwm_init_state(lp->pwm, &state); + /* Legacy platform data compatibility */ + if (lp->pdata->period_ns > 0) + state.period = lp->pdata->period_ns; + lp->needs_pwm_init = false; + } else { + pwm_get_state(lp->pwm, &state); + } state.duty_cycle = div_u64(br * state.period, max_br); state.enabled = state.duty_cycle; @@ -387,7 +396,6 @@ static int lp855x_probe(struct i2c_client *cl) const struct i2c_device_id *id = i2c_client_get_device_id(cl); const struct acpi_device_id *acpi_id = NULL; struct device *dev = &cl->dev; - struct pwm_state pwmstate; struct lp855x *lp; int ret; @@ -470,15 +478,11 @@ static int lp855x_probe(struct i2c_client *cl) else return dev_err_probe(dev, ret, "getting PWM\n"); + lp->needs_pwm_init = false; lp->mode = REGISTER_BASED; dev_dbg(dev, "mode: register based\n"); } else { - pwm_init_state(lp->pwm, &pwmstate); - /* Legacy platform data compatibility */ - if (lp->pdata->period_ns > 0) - pwmstate.period = lp->pdata->period_ns; - pwm_apply_state(lp->pwm, &pwmstate); - + lp->needs_pwm_init = true; lp->mode = PWM_BASED; dev_dbg(dev, "mode: PWM based\n"); } -- GitLab From 5145531be5fbad0e914d1dc1cbd392d7b756abaa Mon Sep 17 00:00:00 2001 From: Artur Weber Date: Fri, 14 Jul 2023 14:14:40 +0200 Subject: [PATCH 0508/3445] backlight: lp855x: Catch errors when changing brightness The lp855x_bl_update_status function's return type is int, but it always returns 0, without checking for the results of the write_byte/pwm_ctrl functions called within. Make this function return the return values of the functions it calls, and modify the lp855x_pwm_ctrl function to return errors. Signed-off-by: Artur Weber Reviewed-by: Daniel Thompson Link: https://lore.kernel.org/r/20230714121440.7717-3-aweber.kernel@gmail.com Signed-off-by: Lee Jones --- drivers/video/backlight/lp855x_bl.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c index 349ec324bc1ea..61a7f45bfad84 100644 --- a/drivers/video/backlight/lp855x_bl.c +++ b/drivers/video/backlight/lp855x_bl.c @@ -217,7 +217,7 @@ err: return ret; } -static void lp855x_pwm_ctrl(struct lp855x *lp, int br, int max_br) +static int lp855x_pwm_ctrl(struct lp855x *lp, int br, int max_br) { struct pwm_state state; @@ -234,23 +234,26 @@ static void lp855x_pwm_ctrl(struct lp855x *lp, int br, int max_br) state.duty_cycle = div_u64(br * state.period, max_br); state.enabled = state.duty_cycle; - pwm_apply_state(lp->pwm, &state); + return pwm_apply_state(lp->pwm, &state); } static int lp855x_bl_update_status(struct backlight_device *bl) { struct lp855x *lp = bl_get_data(bl); int brightness = bl->props.brightness; + int ret; if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) brightness = 0; if (lp->mode == PWM_BASED) - lp855x_pwm_ctrl(lp, brightness, bl->props.max_brightness); + ret = lp855x_pwm_ctrl(lp, brightness, + bl->props.max_brightness); else if (lp->mode == REGISTER_BASED) - lp855x_write_byte(lp, lp->cfg->reg_brightness, (u8)brightness); + ret = lp855x_write_byte(lp, lp->cfg->reg_brightness, + (u8)brightness); - return 0; + return ret; } static const struct backlight_ops lp855x_bl_ops = { -- GitLab From 0723807978b14837262671d30b5cc8b1b5268281 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 26 Jul 2023 19:20:28 -0600 Subject: [PATCH 0509/3445] MIPS: Fixup explicit DT include clean-up Commit 657c45b303f87d77 ("MIPS: Explicitly include correct DT includes") removed a necessary include by mistake and missed adding an explicit include of spinlock.h (from of.h -> kobject.h -> spinlock.h). Fixes: 657c45b303f87d77 ("MIPS: Explicitly include correct DT includes") Reported-by: Geert Uytterhoeven Signed-off-by: Rob Herring Signed-off-by: Thomas Bogendoerfer --- arch/mips/lantiq/xway/gptu.c | 1 + arch/mips/pic32/pic32mzda/config.c | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/mips/lantiq/xway/gptu.c b/arch/mips/lantiq/xway/gptu.c index e254b108fb9ba..8d52001301dee 100644 --- a/arch/mips/lantiq/xway/gptu.c +++ b/arch/mips/lantiq/xway/gptu.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include diff --git a/arch/mips/pic32/pic32mzda/config.c b/arch/mips/pic32/pic32mzda/config.c index 6e94ae66eba82..73be5689e0dfb 100644 --- a/arch/mips/pic32/pic32mzda/config.c +++ b/arch/mips/pic32/pic32mzda/config.c @@ -5,6 +5,7 @@ */ #include #include +#include #include -- GitLab From e1a7566d0955cc5357903c04030aac05ced95939 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 26 Jul 2023 19:20:39 -0600 Subject: [PATCH 0510/3445] MIPS: More explicit DT include clean-ups A couple more clean-ups in the MIPS code. The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it was merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Signed-off-by: Thomas Bogendoerfer --- arch/mips/cavium-octeon/octeon-platform.c | 2 ++ arch/mips/cavium-octeon/octeon-usb.c | 2 ++ arch/mips/ralink/ill_acc.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c index ce05c0dd3acd7..60da1b2091f5e 100644 --- a/arch/mips/cavium-octeon/octeon-platform.c +++ b/arch/mips/cavium-octeon/octeon-platform.c @@ -8,8 +8,10 @@ */ #include +#include #include #include +#include #include #include diff --git a/arch/mips/cavium-octeon/octeon-usb.c b/arch/mips/cavium-octeon/octeon-usb.c index 2add435ad0387..add0f23592b30 100644 --- a/arch/mips/cavium-octeon/octeon-usb.c +++ b/arch/mips/cavium-octeon/octeon-usb.c @@ -15,7 +15,9 @@ #include #include #include +#include #include +#include /* * USB Control Register diff --git a/arch/mips/ralink/ill_acc.c b/arch/mips/ralink/ill_acc.c index f395ae218470f..25341b2319d0f 100644 --- a/arch/mips/ralink/ill_acc.c +++ b/arch/mips/ralink/ill_acc.c @@ -5,8 +5,10 @@ */ #include +#include #include #include +#include #include -- GitLab From ef8365dfaa53c11722904dd590154f981d735754 Mon Sep 17 00:00:00 2001 From: Keguang Zhang Date: Wed, 26 Jul 2023 20:51:30 +0800 Subject: [PATCH 0511/3445] MIPS: loongson32: Remove regs-clk.h Since commit c46496119ed0 ("clk: loongson1: Remove the outdated driver"), no one is using regs-clk.h. Therefore, remove this obsolete header file. Signed-off-by: Keguang Zhang Signed-off-by: Thomas Bogendoerfer --- .../include/asm/mach-loongson32/loongson1.h | 1 - .../include/asm/mach-loongson32/regs-clk.h | 81 ------------------- 2 files changed, 82 deletions(-) delete mode 100644 arch/mips/include/asm/mach-loongson32/regs-clk.h diff --git a/arch/mips/include/asm/mach-loongson32/loongson1.h b/arch/mips/include/asm/mach-loongson32/loongson1.h index 7971272345d31..bc27fcee3176f 100644 --- a/arch/mips/include/asm/mach-loongson32/loongson1.h +++ b/arch/mips/include/asm/mach-loongson32/loongson1.h @@ -45,7 +45,6 @@ #define LS1X_NAND_BASE 0x1fe78000 #define LS1X_CLK_BASE 0x1fe78030 -#include #include #include diff --git a/arch/mips/include/asm/mach-loongson32/regs-clk.h b/arch/mips/include/asm/mach-loongson32/regs-clk.h deleted file mode 100644 index 98136fa8bee14..0000000000000 --- a/arch/mips/include/asm/mach-loongson32/regs-clk.h +++ /dev/null @@ -1,81 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (c) 2011 Zhang, Keguang - * - * Loongson 1 Clock Register Definitions. - */ - -#ifndef __ASM_MACH_LOONGSON32_REGS_CLK_H -#define __ASM_MACH_LOONGSON32_REGS_CLK_H - -#define LS1X_CLK_REG(x) \ - ((void __iomem *)KSEG1ADDR(LS1X_CLK_BASE + (x))) - -#define LS1X_CLK_PLL_FREQ LS1X_CLK_REG(0x0) -#define LS1X_CLK_PLL_DIV LS1X_CLK_REG(0x4) - -#if defined(CONFIG_LOONGSON1_LS1B) -/* Clock PLL Divisor Register Bits */ -#define DIV_DC_EN BIT(31) -#define DIV_DC_RST BIT(30) -#define DIV_CPU_EN BIT(25) -#define DIV_CPU_RST BIT(24) -#define DIV_DDR_EN BIT(19) -#define DIV_DDR_RST BIT(18) -#define RST_DC_EN BIT(5) -#define RST_DC BIT(4) -#define RST_DDR_EN BIT(3) -#define RST_DDR BIT(2) -#define RST_CPU_EN BIT(1) -#define RST_CPU BIT(0) - -#define DIV_DC_SHIFT 26 -#define DIV_CPU_SHIFT 20 -#define DIV_DDR_SHIFT 14 - -#define DIV_DC_WIDTH 4 -#define DIV_CPU_WIDTH 4 -#define DIV_DDR_WIDTH 4 - -#define BYPASS_DC_SHIFT 12 -#define BYPASS_DDR_SHIFT 10 -#define BYPASS_CPU_SHIFT 8 - -#define BYPASS_DC_WIDTH 1 -#define BYPASS_DDR_WIDTH 1 -#define BYPASS_CPU_WIDTH 1 - -#elif defined(CONFIG_LOONGSON1_LS1C) -/* PLL/SDRAM Frequency configuration register Bits */ -#define PLL_VALID BIT(31) -#define FRAC_N GENMASK(23, 16) -#define RST_TIME GENMASK(3, 2) -#define SDRAM_DIV GENMASK(1, 0) - -/* CPU/CAMERA/DC Frequency configuration register Bits */ -#define DIV_DC_EN BIT(31) -#define DIV_DC GENMASK(30, 24) -#define DIV_CAM_EN BIT(23) -#define DIV_CAM GENMASK(22, 16) -#define DIV_CPU_EN BIT(15) -#define DIV_CPU GENMASK(14, 8) -#define DIV_DC_SEL_EN BIT(5) -#define DIV_DC_SEL BIT(4) -#define DIV_CAM_SEL_EN BIT(3) -#define DIV_CAM_SEL BIT(2) -#define DIV_CPU_SEL_EN BIT(1) -#define DIV_CPU_SEL BIT(0) - -#define DIV_DC_SHIFT 24 -#define DIV_CAM_SHIFT 16 -#define DIV_CPU_SHIFT 8 -#define DIV_DDR_SHIFT 0 - -#define DIV_DC_WIDTH 7 -#define DIV_CAM_WIDTH 7 -#define DIV_CPU_WIDTH 7 -#define DIV_DDR_WIDTH 2 - -#endif - -#endif /* __ASM_MACH_LOONGSON32_REGS_CLK_H */ -- GitLab From 20463908951be777b3300c1a3a845877266f8fee Mon Sep 17 00:00:00 2001 From: Keguang Zhang Date: Wed, 26 Jul 2023 20:51:31 +0800 Subject: [PATCH 0512/3445] MIPS: loongson32: Remove regs-rtc.h Since commit 35508d242409 ("MIPS: loongson32: ls1c: Fix hang during startup"), no one is calling ls1x_rtc_set_extclk(). Therefore, remove this obsolete function. Since commit 9fb23090658a ("rtc: Remove the Loongson-1 RTC driver"), no one is using regs-rtc.h. Therefore, remove this obsolete header file. Signed-off-by: Keguang Zhang Signed-off-by: Thomas Bogendoerfer --- .../include/asm/mach-loongson32/loongson1.h | 1 - .../include/asm/mach-loongson32/regs-rtc.h | 19 ------------------- arch/mips/loongson32/common/platform.c | 8 -------- 3 files changed, 28 deletions(-) delete mode 100644 arch/mips/include/asm/mach-loongson32/regs-rtc.h diff --git a/arch/mips/include/asm/mach-loongson32/loongson1.h b/arch/mips/include/asm/mach-loongson32/loongson1.h index bc27fcee3176f..84f45461c8320 100644 --- a/arch/mips/include/asm/mach-loongson32/loongson1.h +++ b/arch/mips/include/asm/mach-loongson32/loongson1.h @@ -46,6 +46,5 @@ #define LS1X_CLK_BASE 0x1fe78030 #include -#include #endif /* __ASM_MACH_LOONGSON32_LOONGSON1_H */ diff --git a/arch/mips/include/asm/mach-loongson32/regs-rtc.h b/arch/mips/include/asm/mach-loongson32/regs-rtc.h deleted file mode 100644 index a3d096be16077..0000000000000 --- a/arch/mips/include/asm/mach-loongson32/regs-rtc.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (c) 2016 Yang Ling - * - * Loongson 1 RTC timer Register Definitions. - */ - -#ifndef __ASM_MACH_LOONGSON32_REGS_RTC_H -#define __ASM_MACH_LOONGSON32_REGS_RTC_H - -#define LS1X_RTC_REG(x) \ - ((void __iomem *)KSEG1ADDR(LS1X_RTC_BASE + (x))) - -#define LS1X_RTC_CTRL LS1X_RTC_REG(0x40) - -#define RTC_EXTCLK_OK (BIT(5) | BIT(8)) -#define RTC_EXTCLK_EN BIT(8) - -#endif /* __ASM_MACH_LOONGSON32_REGS_RTC_H */ diff --git a/arch/mips/loongson32/common/platform.c b/arch/mips/loongson32/common/platform.c index 64d7979394e63..8075590a9f834 100644 --- a/arch/mips/loongson32/common/platform.c +++ b/arch/mips/loongson32/common/platform.c @@ -265,14 +265,6 @@ struct platform_device ls1x_ehci_pdev = { }; /* Real Time Clock */ -void __init ls1x_rtc_set_extclk(struct platform_device *pdev) -{ - u32 val = __raw_readl(LS1X_RTC_CTRL); - - if (!(val & RTC_EXTCLK_OK)) - __raw_writel(val | RTC_EXTCLK_EN, LS1X_RTC_CTRL); -} - struct platform_device ls1x_rtc_pdev = { .name = "ls1x-rtc", .id = -1, -- GitLab From f11a9967413281b49690d864795e7c5f8f8e4fda Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Tue, 25 Jul 2023 14:01:44 +0800 Subject: [PATCH 0513/3445] MIPS: Loongson64: Fix more __iomem attributes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are some __iomem type casting being missed in previous patch. Fix them here. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202307020639.QCZOKp8B-lkp@intel.com/ Signed-off-by: Jiaxun Yang Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Bogendoerfer --- arch/mips/loongson64/smp.c | 160 ++++++++++++++++++------------------- 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/arch/mips/loongson64/smp.c b/arch/mips/loongson64/smp.c index cdecd7af11a6a..e015a26a40f7a 100644 --- a/arch/mips/loongson64/smp.c +++ b/arch/mips/loongson64/smp.c @@ -187,181 +187,181 @@ static void csr_ipi_probe(void) static void ipi_set0_regs_init(void) { - ipi_set0_regs[0] = (void *) + ipi_set0_regs[0] = (void __iomem *) (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + SET0); - ipi_set0_regs[1] = (void *) + ipi_set0_regs[1] = (void __iomem *) (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + SET0); - ipi_set0_regs[2] = (void *) + ipi_set0_regs[2] = (void __iomem *) (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + SET0); - ipi_set0_regs[3] = (void *) + ipi_set0_regs[3] = (void __iomem *) (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + SET0); - ipi_set0_regs[4] = (void *) + ipi_set0_regs[4] = (void __iomem *) (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + SET0); - ipi_set0_regs[5] = (void *) + ipi_set0_regs[5] = (void __iomem *) (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + SET0); - ipi_set0_regs[6] = (void *) + ipi_set0_regs[6] = (void __iomem *) (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + SET0); - ipi_set0_regs[7] = (void *) + ipi_set0_regs[7] = (void __iomem *) (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + SET0); - ipi_set0_regs[8] = (void *) + ipi_set0_regs[8] = (void __iomem *) (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + SET0); - ipi_set0_regs[9] = (void *) + ipi_set0_regs[9] = (void __iomem *) (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + SET0); - ipi_set0_regs[10] = (void *) + ipi_set0_regs[10] = (void __iomem *) (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + SET0); - ipi_set0_regs[11] = (void *) + ipi_set0_regs[11] = (void __iomem *) (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + SET0); - ipi_set0_regs[12] = (void *) + ipi_set0_regs[12] = (void __iomem *) (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + SET0); - ipi_set0_regs[13] = (void *) + ipi_set0_regs[13] = (void __iomem *) (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + SET0); - ipi_set0_regs[14] = (void *) + ipi_set0_regs[14] = (void __iomem *) (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + SET0); - ipi_set0_regs[15] = (void *) + ipi_set0_regs[15] = (void __iomem *) (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + SET0); } static void ipi_clear0_regs_init(void) { - ipi_clear0_regs[0] = (void *) + ipi_clear0_regs[0] = (void __iomem *) (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + CLEAR0); - ipi_clear0_regs[1] = (void *) + ipi_clear0_regs[1] = (void __iomem *) (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + CLEAR0); - ipi_clear0_regs[2] = (void *) + ipi_clear0_regs[2] = (void __iomem *) (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + CLEAR0); - ipi_clear0_regs[3] = (void *) + ipi_clear0_regs[3] = (void __iomem *) (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + CLEAR0); - ipi_clear0_regs[4] = (void *) + ipi_clear0_regs[4] = (void __iomem *) (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + CLEAR0); - ipi_clear0_regs[5] = (void *) + ipi_clear0_regs[5] = (void __iomem *) (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + CLEAR0); - ipi_clear0_regs[6] = (void *) + ipi_clear0_regs[6] = (void __iomem *) (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + CLEAR0); - ipi_clear0_regs[7] = (void *) + ipi_clear0_regs[7] = (void __iomem *) (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + CLEAR0); - ipi_clear0_regs[8] = (void *) + ipi_clear0_regs[8] = (void __iomem *) (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + CLEAR0); - ipi_clear0_regs[9] = (void *) + ipi_clear0_regs[9] = (void __iomem *) (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + CLEAR0); - ipi_clear0_regs[10] = (void *) + ipi_clear0_regs[10] = (void __iomem *) (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + CLEAR0); - ipi_clear0_regs[11] = (void *) + ipi_clear0_regs[11] = (void __iomem *) (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + CLEAR0); - ipi_clear0_regs[12] = (void *) + ipi_clear0_regs[12] = (void __iomem *) (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + CLEAR0); - ipi_clear0_regs[13] = (void *) + ipi_clear0_regs[13] = (void __iomem *) (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + CLEAR0); - ipi_clear0_regs[14] = (void *) + ipi_clear0_regs[14] = (void __iomem *) (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + CLEAR0); - ipi_clear0_regs[15] = (void *) + ipi_clear0_regs[15] = (void __iomem *) (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + CLEAR0); } static void ipi_status0_regs_init(void) { - ipi_status0_regs[0] = (void *) + ipi_status0_regs[0] = (void __iomem *) (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + STATUS0); - ipi_status0_regs[1] = (void *) + ipi_status0_regs[1] = (void __iomem *) (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + STATUS0); - ipi_status0_regs[2] = (void *) + ipi_status0_regs[2] = (void __iomem *) (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + STATUS0); - ipi_status0_regs[3] = (void *) + ipi_status0_regs[3] = (void __iomem *) (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + STATUS0); - ipi_status0_regs[4] = (void *) + ipi_status0_regs[4] = (void __iomem *) (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + STATUS0); - ipi_status0_regs[5] = (void *) + ipi_status0_regs[5] = (void __iomem *) (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + STATUS0); - ipi_status0_regs[6] = (void *) + ipi_status0_regs[6] = (void __iomem *) (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + STATUS0); - ipi_status0_regs[7] = (void *) + ipi_status0_regs[7] = (void __iomem *) (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + STATUS0); - ipi_status0_regs[8] = (void *) + ipi_status0_regs[8] = (void __iomem *) (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + STATUS0); - ipi_status0_regs[9] = (void *) + ipi_status0_regs[9] = (void __iomem *) (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + STATUS0); - ipi_status0_regs[10] = (void *) + ipi_status0_regs[10] = (void __iomem *) (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + STATUS0); - ipi_status0_regs[11] = (void *) + ipi_status0_regs[11] = (void __iomem *) (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + STATUS0); - ipi_status0_regs[12] = (void *) + ipi_status0_regs[12] = (void __iomem *) (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + STATUS0); - ipi_status0_regs[13] = (void *) + ipi_status0_regs[13] = (void __iomem *) (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + STATUS0); - ipi_status0_regs[14] = (void *) + ipi_status0_regs[14] = (void __iomem *) (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + STATUS0); - ipi_status0_regs[15] = (void *) + ipi_status0_regs[15] = (void __iomem *) (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + STATUS0); } static void ipi_en0_regs_init(void) { - ipi_en0_regs[0] = (void *) + ipi_en0_regs[0] = (void __iomem *) (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + EN0); - ipi_en0_regs[1] = (void *) + ipi_en0_regs[1] = (void __iomem *) (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + EN0); - ipi_en0_regs[2] = (void *) + ipi_en0_regs[2] = (void __iomem *) (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + EN0); - ipi_en0_regs[3] = (void *) + ipi_en0_regs[3] = (void __iomem *) (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + EN0); - ipi_en0_regs[4] = (void *) + ipi_en0_regs[4] = (void __iomem *) (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + EN0); - ipi_en0_regs[5] = (void *) + ipi_en0_regs[5] = (void __iomem *) (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + EN0); - ipi_en0_regs[6] = (void *) + ipi_en0_regs[6] = (void __iomem *) (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + EN0); - ipi_en0_regs[7] = (void *) + ipi_en0_regs[7] = (void __iomem *) (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + EN0); - ipi_en0_regs[8] = (void *) + ipi_en0_regs[8] = (void __iomem *) (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + EN0); - ipi_en0_regs[9] = (void *) + ipi_en0_regs[9] = (void __iomem *) (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + EN0); - ipi_en0_regs[10] = (void *) + ipi_en0_regs[10] = (void __iomem *) (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + EN0); - ipi_en0_regs[11] = (void *) + ipi_en0_regs[11] = (void __iomem *) (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + EN0); - ipi_en0_regs[12] = (void *) + ipi_en0_regs[12] = (void __iomem *) (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + EN0); - ipi_en0_regs[13] = (void *) + ipi_en0_regs[13] = (void __iomem *) (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + EN0); - ipi_en0_regs[14] = (void *) + ipi_en0_regs[14] = (void __iomem *) (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + EN0); - ipi_en0_regs[15] = (void *) + ipi_en0_regs[15] = (void __iomem *) (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + EN0); } static void ipi_mailbox_buf_init(void) { - ipi_mailbox_buf[0] = (void *) + ipi_mailbox_buf[0] = (void __iomem *) (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + BUF); - ipi_mailbox_buf[1] = (void *) + ipi_mailbox_buf[1] = (void __iomem *) (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + BUF); - ipi_mailbox_buf[2] = (void *) + ipi_mailbox_buf[2] = (void __iomem *) (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + BUF); - ipi_mailbox_buf[3] = (void *) + ipi_mailbox_buf[3] = (void __iomem *) (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + BUF); - ipi_mailbox_buf[4] = (void *) + ipi_mailbox_buf[4] = (void __iomem *) (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + BUF); - ipi_mailbox_buf[5] = (void *) + ipi_mailbox_buf[5] = (void __iomem *) (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + BUF); - ipi_mailbox_buf[6] = (void *) + ipi_mailbox_buf[6] = (void __iomem *) (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + BUF); - ipi_mailbox_buf[7] = (void *) + ipi_mailbox_buf[7] = (void __iomem *) (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + BUF); - ipi_mailbox_buf[8] = (void *) + ipi_mailbox_buf[8] = (void __iomem *) (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + BUF); - ipi_mailbox_buf[9] = (void *) + ipi_mailbox_buf[9] = (void __iomem *) (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + BUF); - ipi_mailbox_buf[10] = (void *) + ipi_mailbox_buf[10] = (void __iomem *) (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + BUF); - ipi_mailbox_buf[11] = (void *) + ipi_mailbox_buf[11] = (void __iomem *) (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + BUF); - ipi_mailbox_buf[12] = (void *) + ipi_mailbox_buf[12] = (void __iomem *) (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + BUF); - ipi_mailbox_buf[13] = (void *) + ipi_mailbox_buf[13] = (void __iomem *) (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + BUF); - ipi_mailbox_buf[14] = (void *) + ipi_mailbox_buf[14] = (void __iomem *) (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + BUF); - ipi_mailbox_buf[15] = (void *) + ipi_mailbox_buf[15] = (void __iomem *) (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + BUF); } -- GitLab From c8a039436525072af7e77f540d21f0d312fc7c38 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 22 Jul 2023 22:26:49 +0200 Subject: [PATCH 0514/3445] leds: ns2: Slightly simplify a memory allocation Use devm_kcalloc() instead of devm_kzalloc()+array_size(). Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/560b8f140c19a7da40f5e9540c3ef312969b0dc4.1690057595.git.christophe.jaillet@wanadoo.fr Signed-off-by: Lee Jones --- drivers/leds/leds-ns2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index 1677d66d8b0e3..f3010c472bbd4 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -247,7 +247,7 @@ static int ns2_led_probe(struct platform_device *pdev) if (!count) return -ENODEV; - leds = devm_kzalloc(dev, array_size(sizeof(*leds), count), GFP_KERNEL); + leds = devm_kcalloc(dev, count, sizeof(*leds), GFP_KERNEL); if (!leds) return -ENOMEM; -- GitLab From fe1328b5b2a087221e31da77e617f4c2b70f3b7f Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Fri, 21 Jul 2023 09:29:03 +0000 Subject: [PATCH 0515/3445] backlight: gpio_backlight: Drop output GPIO direction check for initial power state So, let's drop output GPIO direction check and only check GPIO value to set the initial power state. Fixes: 706dc68102bc ("backlight: gpio: Explicitly set the direction of the GPIO") Signed-off-by: Liu Ying Reviewed-by: Andy Shevchenko Acked-by: Linus Walleij Acked-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20230721093342.1532531-1-victor.liu@nxp.com Signed-off-by: Lee Jones --- drivers/video/backlight/gpio_backlight.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/video/backlight/gpio_backlight.c b/drivers/video/backlight/gpio_backlight.c index 6f78d928f054a..38c46936fdcd2 100644 --- a/drivers/video/backlight/gpio_backlight.c +++ b/drivers/video/backlight/gpio_backlight.c @@ -87,8 +87,7 @@ static int gpio_backlight_probe(struct platform_device *pdev) /* Not booted with device tree or no phandle link to the node */ bl->props.power = def_value ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; - else if (gpiod_get_direction(gbl->gpiod) == 0 && - gpiod_get_value_cansleep(gbl->gpiod) == 0) + else if (gpiod_get_value_cansleep(gbl->gpiod) == 0) bl->props.power = FB_BLANK_POWERDOWN; else bl->props.power = FB_BLANK_UNBLANK; -- GitLab From 02a3fa1edeb4fa7bac2cc7f604adf23e34cb2e40 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 24 Jul 2023 17:02:58 -0600 Subject: [PATCH 0516/3445] dt-bindings: leds: Convert Panasonic AN30259A to DT schema Convert the Panasonic AN30259A 3-channel LED controller binding to DT schema format. Signed-off-by: Rob Herring Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230724230258.1017258-1-robh@kernel.org Signed-off-by: Lee Jones --- .../bindings/leds/leds-an30259a.txt | 55 ------------ .../bindings/leds/panasonic,an30259a.yaml | 84 +++++++++++++++++++ 2 files changed, 84 insertions(+), 55 deletions(-) delete mode 100644 Documentation/devicetree/bindings/leds/leds-an30259a.txt create mode 100644 Documentation/devicetree/bindings/leds/panasonic,an30259a.yaml diff --git a/Documentation/devicetree/bindings/leds/leds-an30259a.txt b/Documentation/devicetree/bindings/leds/leds-an30259a.txt deleted file mode 100644 index cbd833906b2b5..0000000000000 --- a/Documentation/devicetree/bindings/leds/leds-an30259a.txt +++ /dev/null @@ -1,55 +0,0 @@ -* Panasonic AN30259A 3-channel LED driver - -The AN30259A is a LED controller capable of driving three LEDs independently. It supports -constant current output and sloping current output modes. The chip is connected over I2C. - -Required properties: - - compatible: Must be "panasonic,an30259a". - - reg: I2C slave address. - - #address-cells: Must be 1. - - #size-cells: Must be 0. - -Each LED is represented as a sub-node of the panasonic,an30259a node. - -Required sub-node properties: - - reg: Pin that the LED is connected to. Must be 1, 2, or 3. - -Optional sub-node properties: - - function : - see Documentation/devicetree/bindings/leds/common.txt - - color : - see Documentation/devicetree/bindings/leds/common.txt - - label : - see Documentation/devicetree/bindings/leds/common.txt (deprecated) - - linux,default-trigger : - see Documentation/devicetree/bindings/leds/common.txt - -Example: - -#include - -led-controller@30 { - compatible = "panasonic,an30259a"; - reg = <0x30>; - #address-cells = <1>; - #size-cells = <0>; - - led@1 { - reg = <1>; - linux,default-trigger = "heartbeat"; - function = LED_FUNCTION_INDICATOR; - color = ; - }; - - led@2 { - reg = <2>; - function = LED_FUNCTION_INDICATOR; - color = ; - }; - - led@3 { - reg = <3>; - function = LED_FUNCTION_INDICATOR; - color = ; - }; -}; diff --git a/Documentation/devicetree/bindings/leds/panasonic,an30259a.yaml b/Documentation/devicetree/bindings/leds/panasonic,an30259a.yaml new file mode 100644 index 0000000000000..e918dceea0828 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/panasonic,an30259a.yaml @@ -0,0 +1,84 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/panasonic,an30259a.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Panasonic AN30259A 3-channel LED controller + +maintainers: + - Iskren Chernev + +description: + The AN30259A is a LED controller capable of driving three LEDs independently. + It supports constant current output and sloping current output modes. The chip + is connected over I2C. + +properties: + compatible: + const: panasonic,an30259a + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^led@[1-3]$": + $ref: common.yaml# + unevaluatedProperties: false + + properties: + reg: + enum: [ 1, 2, 3 ] + +required: + - compatible + - reg + - "#address-cells" + - "#size-cells" + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + led-controller@30 { + compatible = "panasonic,an30259a"; + reg = <0x30>; + #address-cells = <1>; + #size-cells = <0>; + + led@1 { + reg = <1>; + linux,default-trigger = "heartbeat"; + function = LED_FUNCTION_INDICATOR; + color = ; + }; + + led@2 { + reg = <2>; + function = LED_FUNCTION_INDICATOR; + color = ; + }; + + led@3 { + reg = <3>; + function = LED_FUNCTION_INDICATOR; + color = ; + }; + }; + }; +... -- GitLab From 05a576059ac23355a86e4be058cb43997d83c7fd Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Tue, 25 Jul 2023 17:57:19 +0800 Subject: [PATCH 0517/3445] leds: flash: leds-qcom-flash: Declare the driver as a module Explain in Kconfig that the driver can be compiled as a module. Signed-off-by: Fenglin Wu Link: https://lore.kernel.org/r/20230725-leds-qcom-flash-driver-tiny-fixes-v2-1-0f5cbce5fed0@quicinc.com Signed-off-by: Lee Jones --- drivers/leds/flash/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig index 4ed2efc654345..4e08dbc057096 100644 --- a/drivers/leds/flash/Kconfig +++ b/drivers/leds/flash/Kconfig @@ -89,6 +89,8 @@ config LEDS_QCOM_FLASH the total LED current will be split symmetrically on each channel and they will be enabled/disabled at the same time. + This driver can be built as a module, it will be called "leds-qcom-flash". + config LEDS_RT4505 tristate "LED support for RT4505 flashlight controller" depends on I2C && OF -- GitLab From 7c47381c8664d55861036d1d858daf5e9d5d67b8 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Tue, 25 Jul 2023 17:57:20 +0800 Subject: [PATCH 0518/3445] leds: flash: leds-qcom-flash: Turn off LED before setting flash current Strobe off the LED before setting flash current to avoid it's being enabled with an incorrect current if it has been working in torch mode. Signed-off-by: Fenglin Wu Link: https://lore.kernel.org/r/20230725-leds-qcom-flash-driver-tiny-fixes-v2-2-0f5cbce5fed0@quicinc.com Signed-off-by: Lee Jones --- drivers/leds/flash/leds-qcom-flash.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/leds/flash/leds-qcom-flash.c b/drivers/leds/flash/leds-qcom-flash.c index b089ca1a19012..29cf094794227 100644 --- a/drivers/leds/flash/leds-qcom-flash.c +++ b/drivers/leds/flash/leds-qcom-flash.c @@ -309,6 +309,10 @@ static int qcom_flash_strobe_set(struct led_classdev_flash *fled_cdev, bool stat struct qcom_flash_led *led = flcdev_to_qcom_fled(fled_cdev); int rc; + rc = set_flash_strobe(led, SW_STROBE, false); + if (rc) + return rc; + rc = set_flash_current(led, led->flash_current_ma, FLASH_MODE); if (rc) return rc; -- GitLab From 546924102de8327a5b2095d2134faed6de971476 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Tue, 25 Jul 2023 17:57:21 +0800 Subject: [PATCH 0519/3445] leds: flash: leds-qcom-flash: Put child node if registration failed Put the child node if register flash LED device failed. Signed-off-by: Fenglin Wu Link: https://lore.kernel.org/r/20230725-leds-qcom-flash-driver-tiny-fixes-v2-3-0f5cbce5fed0@quicinc.com Signed-off-by: Lee Jones --- drivers/leds/flash/leds-qcom-flash.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/leds/flash/leds-qcom-flash.c b/drivers/leds/flash/leds-qcom-flash.c index 29cf094794227..a73d3ea5c97a3 100644 --- a/drivers/leds/flash/leds-qcom-flash.c +++ b/drivers/leds/flash/leds-qcom-flash.c @@ -749,6 +749,7 @@ static int qcom_flash_led_probe(struct platform_device *pdev) return 0; release: + fwnode_handle_put(child); while (flash_data->v4l2_flash[flash_data->leds_count] && flash_data->leds_count) v4l2_flash_release(flash_data->v4l2_flash[flash_data->leds_count--]); return rc; -- GitLab From 841165267827955bb3295b066cb6a906ba9265c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 28 Jul 2023 08:57:39 +0200 Subject: [PATCH 0520/3445] leds: qcom-lpg: Drop assignment to struct pwmchip::base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit f9a8ee8c8bcd ("pwm: Always allocate PWM chip base ID dynamically") there is no effect any more for assigning this variable. See pwmchip_add() which unconditionally overwrites this member. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230728065739.580281-1-u.kleine-koenig@pengutronix.de Signed-off-by: Lee Jones --- drivers/leds/rgb/leds-qcom-lpg.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c index fd7676aa243d5..df469aaa7e6e7 100644 --- a/drivers/leds/rgb/leds-qcom-lpg.c +++ b/drivers/leds/rgb/leds-qcom-lpg.c @@ -1092,7 +1092,6 @@ static int lpg_add_pwm(struct lpg *lpg) { int ret; - lpg->pwm.base = -1; lpg->pwm.dev = lpg->dev; lpg->pwm.npwm = lpg->num_channels; lpg->pwm.ops = &lpg_pwm_ops; -- GitLab From a6de66607a19095a1bc74aaefff44c9a5ca11da0 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Sun, 16 Jul 2023 16:46:05 +0200 Subject: [PATCH 0521/3445] mtd: rawnand: qcom: Use the BIT() macro Fix the following checkpatch warning: "CHECK: Prefer using the BIT macro" Signed-off-by: Miquel Raynal Acked-by: Manivannan Sadhasivam Reviewed-by: Tudor Ambarus Link: https://lore.kernel.org/linux-mtd/20230716144612.32132-2-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/qcom_nandc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index b1e69d634d4a8..023c8b36426bd 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -123,8 +123,8 @@ /* NAND_ERASED_CW_DETECT_CFG bits */ #define ERASED_CW_ECC_MASK 1 #define AUTO_DETECT_RES 0 -#define MASK_ECC (1 << ERASED_CW_ECC_MASK) -#define RESET_ERASED_DET (1 << AUTO_DETECT_RES) +#define MASK_ECC BIT(ERASED_CW_ECC_MASK) +#define RESET_ERASED_DET BIT(AUTO_DETECT_RES) #define ACTIVE_ERASED_DET (0 << AUTO_DETECT_RES) #define CLR_ERASED_PAGE_DET (RESET_ERASED_DET | MASK_ECC) #define SET_ERASED_PAGE_DET (ACTIVE_ERASED_DET | MASK_ECC) -- GitLab From 428771b61afdea898abd8724777cc36912566017 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Sun, 16 Jul 2023 16:46:06 +0200 Subject: [PATCH 0522/3445] mtd: rawnand: qcom: Use u8 instead of uint8_t Fix the following checkpatch warning: "CHECK: Prefer kernel type 'u8' over 'uint8_t'" Signed-off-by: Miquel Raynal Acked-by: Manivannan Sadhasivam Reviewed-by: Tudor Ambarus Link: https://lore.kernel.org/linux-mtd/20230716144612.32132-3-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/qcom_nandc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 023c8b36426bd..0136df01738e2 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -212,7 +212,7 @@ nandc_set_reg(chip, reg, \ /* Returns the dma address for reg read buffer */ #define reg_buf_dma_addr(chip, vaddr) \ ((chip)->reg_read_dma + \ - ((uint8_t *)(vaddr) - (uint8_t *)(chip)->reg_read_buf)) + ((u8 *)(vaddr) - (u8 *)(chip)->reg_read_buf)) #define QPIC_PER_CW_CMD_ELEMENTS 32 #define QPIC_PER_CW_CMD_SGL 32 @@ -1884,7 +1884,7 @@ static void qcom_nandc_codeword_fixup(struct qcom_nand_host *host, int page) } /* implements ecc->read_page() */ -static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf, +static int qcom_nandc_read_page(struct nand_chip *chip, u8 *buf, int oob_required, int page) { struct qcom_nand_host *host = to_qcom_nand_host(chip); @@ -1912,7 +1912,7 @@ static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf, } /* implements ecc->read_page_raw() */ -static int qcom_nandc_read_page_raw(struct nand_chip *chip, uint8_t *buf, +static int qcom_nandc_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_required, int page) { struct mtd_info *mtd = nand_to_mtd(chip); @@ -1958,7 +1958,7 @@ static int qcom_nandc_read_oob(struct nand_chip *chip, int page) } /* implements ecc->write_page() */ -static int qcom_nandc_write_page(struct nand_chip *chip, const uint8_t *buf, +static int qcom_nandc_write_page(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { struct qcom_nand_host *host = to_qcom_nand_host(chip); @@ -2035,7 +2035,7 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const uint8_t *buf, /* implements ecc->write_page_raw() */ static int qcom_nandc_write_page_raw(struct nand_chip *chip, - const uint8_t *buf, int oob_required, + const u8 *buf, int oob_required, int page) { struct mtd_info *mtd = nand_to_mtd(chip); -- GitLab From 062d8acb1941d4555efbccf0e54214b2f85c02d3 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Sun, 16 Jul 2023 16:46:07 +0200 Subject: [PATCH 0523/3445] mtd: rawnand: qcom: Fix alignment with open parenthesis Fix the following checkpatch warning: "CHECK: Alignment should match open parenthesis" Signed-off-by: Miquel Raynal Acked-by: Manivannan Sadhasivam Reviewed-by: Tudor Ambarus Link: https://lore.kernel.org/linux-mtd/20230716144612.32132-4-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/qcom_nandc.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 0136df01738e2..54a7b49bda875 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -2348,7 +2348,7 @@ static int qcom_nand_ooblayout_ecc(struct mtd_info *mtd, int section, } static int qcom_nand_ooblayout_free(struct mtd_info *mtd, int section, - struct mtd_oob_region *oobregion) + struct mtd_oob_region *oobregion) { struct nand_chip *chip = mtd_to_nand(mtd); struct qcom_nand_host *host = to_qcom_nand_host(chip); @@ -2593,7 +2593,7 @@ static int qcom_op_cmd_mapping(struct qcom_nand_controller *nandc, u8 cmd, /* NAND framework ->exec_op() hooks and related helpers */ static void qcom_parse_instructions(struct nand_chip *chip, const struct nand_subop *subop, - struct qcom_op *q_op) + struct qcom_op *q_op) { struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); const struct nand_op_instr *instr = NULL; @@ -3089,19 +3089,17 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) */ nandc->buf_size = 532; - nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size, - GFP_KERNEL); + nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size, GFP_KERNEL); if (!nandc->data_buffer) return -ENOMEM; - nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs), - GFP_KERNEL); + nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs), GFP_KERNEL); if (!nandc->regs) return -ENOMEM; - nandc->reg_read_buf = devm_kcalloc(nandc->dev, - MAX_REG_RD, sizeof(*nandc->reg_read_buf), - GFP_KERNEL); + nandc->reg_read_buf = devm_kcalloc(nandc->dev, MAX_REG_RD, + sizeof(*nandc->reg_read_buf), + GFP_KERNEL); if (!nandc->reg_read_buf) return -ENOMEM; -- GitLab From 3b645b384bb3d1f30c3ac4b8fd5fcdf9d5493f93 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Sun, 16 Jul 2023 16:46:08 +0200 Subject: [PATCH 0524/3445] mtd: rawnand: qcom: Fix the spacing Fix following checkpatch warning: "CHECK: Please don't use multiple blank lines" "CHECK: Please use a blank line after function/struct/union/enum declarations" Signed-off-by: Miquel Raynal Acked-by: Manivannan Sadhasivam Reviewed-by: Tudor Ambarus Link: https://lore.kernel.org/linux-mtd/20230716144612.32132-5-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/qcom_nandc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 54a7b49bda875..554cca3801daf 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -1997,7 +1997,6 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const u8 *buf, oob_size = ecc->bytes; } - write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size, i == (ecc->steps - 1) ? NAND_BAM_NO_EOT : 0); @@ -2373,6 +2372,7 @@ qcom_nandc_calc_ecc_bytes(int step_size, int strength) { return strength == 4 ? 12 : 16; } + NAND_ECC_CAPS_SINGLE(qcom_nandc_ecc_caps, qcom_nandc_calc_ecc_bytes, NANDC_STEP_SIZE, 4, 8); -- GitLab From fd29ba6707f9b81e8c79a25f25d76a1d39fd60c9 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Sun, 16 Jul 2023 16:46:09 +0200 Subject: [PATCH 0525/3445] mtd: rawnand: qcom: Fix wrong indentation The main "for" loop in qcom_read_status_exec() does guard the following to if's which are badly indented. Fix the indentation. Signed-off-by: Miquel Raynal Acked-by: Manivannan Sadhasivam Reviewed-by: Tudor Ambarus Link: https://lore.kernel.org/linux-mtd/20230716144612.32132-6-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/qcom_nandc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 554cca3801daf..3adc40ef5cf6e 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -2722,12 +2722,12 @@ static int qcom_read_status_exec(struct nand_chip *chip, for (i = 0; i < num_cw; i++) { flash_status = le32_to_cpu(nandc->reg_read_buf[i]); - if (flash_status & FS_MPU_ERR) - host->status &= ~NAND_STATUS_WP; + if (flash_status & FS_MPU_ERR) + host->status &= ~NAND_STATUS_WP; - if (flash_status & FS_OP_ERR || - (i == (num_cw - 1) && (flash_status & FS_DEVICE_STS_ERR))) - host->status |= NAND_STATUS_FAIL; + if (flash_status & FS_OP_ERR || + (i == (num_cw - 1) && (flash_status & FS_DEVICE_STS_ERR))) + host->status |= NAND_STATUS_FAIL; } flash_status = host->status; -- GitLab From 548b7509d92d1349b01ed2293dcdde88f3d7a907 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Sun, 16 Jul 2023 16:46:10 +0200 Subject: [PATCH 0526/3445] mtd: rawnand: qcom: Fix a typo Fix the following checkpatch warning: CHECK: 'tranasction' may be misspelled - perhaps 'transaction'? Signed-off-by: Miquel Raynal Acked-by: Manivannan Sadhasivam Reviewed-by: Tudor Ambarus Link: https://lore.kernel.org/linux-mtd/20230716144612.32132-7-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/qcom_nandc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 3adc40ef5cf6e..cb6ccaa19224d 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -3144,7 +3144,7 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) /* * Initially allocate BAM transaction to read ONFI param page. * After detecting all the devices, this BAM transaction will - * be freed and the next BAM tranasction will be allocated with + * be freed and the next BAM transaction will be allocated with * maximum codeword size */ nandc->max_cwperpage = 1; -- GitLab From e260efea80e9cab8ad9dea1a03db11225df720f3 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Sun, 16 Jul 2023 16:46:11 +0200 Subject: [PATCH 0527/3445] mtd: rawnand: qcom: Early structure initialization Instead of allocating a structure on the stack with random data and then expect the callee to perform the initialization (which is, in general, error prone), prefer zeroing the structure explicitly at allocation and provide the already zeroed area, so no explicit memset operation is needed. It is probably safer to do so, so we limit the timeframe when dirty data could actually be accessed by mistake. Signed-off-by: Miquel Raynal Acked-by: Manivannan Sadhasivam Reviewed-by: Tudor Ambarus Link: https://lore.kernel.org/linux-mtd/20230716144612.32132-8-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/qcom_nandc.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index cb6ccaa19224d..4fc8dafa8f035 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -2600,8 +2600,6 @@ static void qcom_parse_instructions(struct nand_chip *chip, unsigned int op_id; int i; - memset(q_op, 0, sizeof(*q_op)); - for (op_id = 0; op_id < subop->ninstrs; op_id++) { unsigned int offset, naddrs; const u8 *addrs; @@ -2681,7 +2679,7 @@ static int qcom_read_status_exec(struct nand_chip *chip, struct qcom_nand_host *host = to_qcom_nand_host(chip); struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; - struct qcom_op q_op; + struct qcom_op q_op = {}; const struct nand_op_instr *instr = NULL; unsigned int op_id = 0; unsigned int len = 0; @@ -2744,7 +2742,7 @@ static int qcom_read_id_type_exec(struct nand_chip *chip, const struct nand_subo { struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); struct qcom_nand_host *host = to_qcom_nand_host(chip); - struct qcom_op q_op; + struct qcom_op q_op = {}; const struct nand_op_instr *instr = NULL; unsigned int op_id = 0; unsigned int len = 0; @@ -2795,7 +2793,7 @@ static int qcom_misc_cmd_type_exec(struct nand_chip *chip, const struct nand_sub { struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); struct qcom_nand_host *host = to_qcom_nand_host(chip); - struct qcom_op q_op; + struct qcom_op q_op = {}; int ret = 0; qcom_parse_instructions(chip, subop, &q_op); @@ -2838,7 +2836,7 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_ { struct qcom_nand_host *host = to_qcom_nand_host(chip); struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - struct qcom_op q_op; + struct qcom_op q_op = {}; const struct nand_op_instr *instr = NULL; unsigned int op_id = 0; unsigned int len = 0; @@ -2935,7 +2933,7 @@ static int qcom_erase_cmd_type_exec(struct nand_chip *chip, const struct nand_su { struct qcom_nand_host *host = to_qcom_nand_host(chip); struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - struct qcom_op q_op; + struct qcom_op q_op = {}; int ret = 0; qcom_parse_instructions(chip, subop, &q_op); -- GitLab From e2532429312d089cf0d13bcb411433d85aef98f0 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Sun, 16 Jul 2023 16:46:12 +0200 Subject: [PATCH 0528/3445] mtd: rawnand: qcom: Fix address parsing within ->exec_op() The naddrs variable is initialized but not used. Fixing this could have been a matter of dropping the variable, but the right way to do it looks a bit more complex: we can avoid useless writes to the q_op structure by using it. In practice we could even have possible out-of-bound bugs with the existing implementation. Let's fix all that by just performing the right number of assignments in the addr{1,2}_reg fields. Fixes: 89550beb098e ("mtd: rawnand: qcom: Implement exec_op()") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202307131959.PdPSC86K-lkp@intel.com/ Closes: https://lore.kernel.org/oe-kbuild-all/202307131730.NOYbcjBr-lkp@intel.com/ Signed-off-by: Miquel Raynal Acked-by: Manivannan Sadhasivam Reviewed-by: Tudor Ambarus Link: https://lore.kernel.org/linux-mtd/20230716144612.32132-9-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/qcom_nandc.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 4fc8dafa8f035..dc8ca60fc2e2f 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -2616,12 +2616,13 @@ static void qcom_parse_instructions(struct nand_chip *chip, offset = nand_subop_get_addr_start_off(subop, op_id); naddrs = nand_subop_get_num_addr_cyc(subop, op_id); addrs = &instr->ctx.addr.addrs[offset]; - for (i = 0; i < MAX_ADDRESS_CYCLE; i++) { - if (i < 4) - q_op->addr1_reg |= (u32)addrs[i] << i * 8; - else - q_op->addr2_reg |= addrs[i]; - } + + for (i = 0; i < min_t(unsigned int, 4, naddrs); i++) + q_op->addr1_reg |= addrs[i] << (i * 8); + + if (naddrs > 4) + q_op->addr2_reg |= addrs[4]; + q_op->rdy_delay_ns = instr->delay_ns; break; -- GitLab From 4622daf4b5c89cd6a689910c523b8185b8a20338 Mon Sep 17 00:00:00 2001 From: Arseniy Krasnov Date: Fri, 28 Jul 2023 12:38:10 +0300 Subject: [PATCH 0529/3445] mtd: rawnand: meson: fix build error Fixes the following build error: drivers/mtd/nand/raw/meson_nand.c:244:59: error: initializer element is not a compile-time constant static const struct nand_ecc_step_info axg_stepinfo[] = { axg_stepinfo_1024, axg_stepinfo_512 }; ^~~~~~~~~~~~~~~~~ Fixes: 0e1db39336d8 ("mtd: rawnand: meson: support for 512B ECC step size") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202307281007.MMuVjmJ9-lkp@intel.com/ Signed-off-by: Arseniy Krasnov Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230728093810.2985324-1-AVKrasnov@sberdevices.ru --- drivers/mtd/nand/raw/meson_nand.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c index 9bdea97abe4cc..04c3fdf713e72 100644 --- a/drivers/mtd/nand/raw/meson_nand.c +++ b/drivers/mtd/nand/raw/meson_nand.c @@ -229,20 +229,20 @@ NAND_ECC_CAPS_SINGLE(meson_gxl_ecc_caps, meson_nand_calc_ecc_bytes, 1024, 8, 24, 30, 40, 50, 60); static const int axg_stepinfo_strengths[] = { 8 }; -static const struct nand_ecc_step_info axg_stepinfo_1024 = { - .stepsize = 1024, - .strengths = axg_stepinfo_strengths, - .nstrengths = ARRAY_SIZE(axg_stepinfo_strengths) -}; -static const struct nand_ecc_step_info axg_stepinfo_512 = { - .stepsize = 512, - .strengths = axg_stepinfo_strengths, - .nstrengths = ARRAY_SIZE(axg_stepinfo_strengths) +static const struct nand_ecc_step_info axg_stepinfo[] = { + { + .stepsize = 1024, + .strengths = axg_stepinfo_strengths, + .nstrengths = ARRAY_SIZE(axg_stepinfo_strengths) + }, + { + .stepsize = 512, + .strengths = axg_stepinfo_strengths, + .nstrengths = ARRAY_SIZE(axg_stepinfo_strengths) + }, }; -static const struct nand_ecc_step_info axg_stepinfo[] = { axg_stepinfo_1024, axg_stepinfo_512 }; - static const struct nand_ecc_caps meson_axg_ecc_caps = { .stepinfos = axg_stepinfo, .nstepinfos = ARRAY_SIZE(axg_stepinfo), -- GitLab From cbc02854331edc6dc22d8b77b6e22e38ebc7dd51 Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Wed, 26 Jul 2023 22:58:17 -0400 Subject: [PATCH 0530/3445] XArray: Do not return sibling entries from xa_load() It is possible for xa_load() to observe a sibling entry pointing to another sibling entry. An example: Thread A: Thread B: xa_store_range(xa, entry, 188, 191, gfp); xa_load(xa, 191); entry = xa_entry(xa, node, 63); [entry is a sibling of 188] xa_store_range(xa, entry, 184, 191, gfp); if (xa_is_sibling(entry)) offset = xa_to_sibling(entry); entry = xa_entry(xas->xa, node, offset); [entry is now a sibling of 184] It is sufficient to go around this loop until we hit a non-sibling entry. Sibling entries always point earlier in the node, so we are guaranteed to terminate this search. Signed-off-by: Matthew Wilcox (Oracle) Fixes: 6b24ca4a1a8d ("mm: Use multi-index entries in the page cache") Cc: stable@vger.kernel.org --- lib/xarray.c | 2 +- tools/testing/radix-tree/multiorder.c | 68 ++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/lib/xarray.c b/lib/xarray.c index 2071a3718f4ed..142e36f9dfda1 100644 --- a/lib/xarray.c +++ b/lib/xarray.c @@ -206,7 +206,7 @@ static void *xas_descend(struct xa_state *xas, struct xa_node *node) void *entry = xa_entry(xas->xa, node, offset); xas->xa_node = node; - if (xa_is_sibling(entry)) { + while (xa_is_sibling(entry)) { offset = xa_to_sibling(entry); entry = xa_entry(xas->xa, node, offset); if (node->shift && xa_is_node(entry)) diff --git a/tools/testing/radix-tree/multiorder.c b/tools/testing/radix-tree/multiorder.c index e00520cc63498..cffaf2245d4f1 100644 --- a/tools/testing/radix-tree/multiorder.c +++ b/tools/testing/radix-tree/multiorder.c @@ -159,7 +159,7 @@ void multiorder_tagged_iteration(struct xarray *xa) item_kill_tree(xa); } -bool stop_iteration = false; +bool stop_iteration; static void *creator_func(void *ptr) { @@ -201,6 +201,7 @@ static void multiorder_iteration_race(struct xarray *xa) pthread_t worker_thread[num_threads]; int i; + stop_iteration = false; pthread_create(&worker_thread[0], NULL, &creator_func, xa); for (i = 1; i < num_threads; i++) pthread_create(&worker_thread[i], NULL, &iterator_func, xa); @@ -211,6 +212,61 @@ static void multiorder_iteration_race(struct xarray *xa) item_kill_tree(xa); } +static void *load_creator(void *ptr) +{ + /* 'order' is set up to ensure we have sibling entries */ + unsigned int order; + struct radix_tree_root *tree = ptr; + int i; + + rcu_register_thread(); + item_insert_order(tree, 3 << RADIX_TREE_MAP_SHIFT, 0); + item_insert_order(tree, 2 << RADIX_TREE_MAP_SHIFT, 0); + for (i = 0; i < 10000; i++) { + for (order = 1; order < RADIX_TREE_MAP_SHIFT; order++) { + unsigned long index = (3 << RADIX_TREE_MAP_SHIFT) - + (1 << order); + item_insert_order(tree, index, order); + item_delete_rcu(tree, index); + } + } + rcu_unregister_thread(); + + stop_iteration = true; + return NULL; +} + +static void *load_worker(void *ptr) +{ + unsigned long index = (3 << RADIX_TREE_MAP_SHIFT) - 1; + + rcu_register_thread(); + while (!stop_iteration) { + struct item *item = xa_load(ptr, index); + assert(!xa_is_internal(item)); + } + rcu_unregister_thread(); + + return NULL; +} + +static void load_race(struct xarray *xa) +{ + const int num_threads = sysconf(_SC_NPROCESSORS_ONLN) * 4; + pthread_t worker_thread[num_threads]; + int i; + + stop_iteration = false; + pthread_create(&worker_thread[0], NULL, &load_creator, xa); + for (i = 1; i < num_threads; i++) + pthread_create(&worker_thread[i], NULL, &load_worker, xa); + + for (i = 0; i < num_threads; i++) + pthread_join(worker_thread[i], NULL); + + item_kill_tree(xa); +} + static DEFINE_XARRAY(array); void multiorder_checks(void) @@ -218,12 +274,20 @@ void multiorder_checks(void) multiorder_iteration(&array); multiorder_tagged_iteration(&array); multiorder_iteration_race(&array); + load_race(&array); radix_tree_cpu_dead(0); } -int __weak main(void) +int __weak main(int argc, char **argv) { + int opt; + + while ((opt = getopt(argc, argv, "ls:v")) != -1) { + if (opt == 'v') + test_verbose++; + } + rcu_register_thread(); radix_tree_init(); multiorder_checks(); -- GitLab From 88cc47e24597971b05b6e94c28a2fc81d2a8d61a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 28 Jul 2023 17:26:54 -0300 Subject: [PATCH 0531/3445] perf build: Define YYNOMEM as YYNOABORT for bison < 3.81 YYNOMEM was introduced in bison 3.81, so define it as YYABORT for older versions, which should provide the previous perf behaviour. Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/Build | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 96f4ea1d45c56..9c6c4475524b9 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -301,6 +301,12 @@ ifeq ($(BISON_GE_35),1) else bison_flags += -w endif + +BISON_LT_381 := $(shell expr $(shell $(BISON) --version | grep bison | sed -e 's/.\+ \([0-9]\+\).\([0-9]\+\).\([0-9]\+\)/\1\2\3/g') \< 381) +ifeq ($(BISON_LT_381),1) + bison_flags += -DYYNOMEM=YYABORT +endif + CFLAGS_parse-events-bison.o += $(bison_flags) CFLAGS_pmu-bison.o += -DYYLTYPE_IS_TRIVIAL=0 $(bison_flags) CFLAGS_expr-bison.o += -DYYLTYPE_IS_TRIVIAL=0 $(bison_flags) -- GitLab From 9462e4de62755c85867991a4beccff15377d0e95 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 27 Jun 2023 11:10:23 -0700 Subject: [PATCH 0532/3445] perf parse-event: Add memory allocation test for name terms If the name memory allocation fails then propagate to the parser. Committer notes: Use $(BISON_FALLBACK_FLAGS) on the bison call so that we continue building with older bison versions, before 3.81, where YYNOMEM isn't present. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: bpf@vger.kernel.org Link: https://lore.kernel.org/r/20230627181030.95608-7-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/Build | 2 +- tools/perf/util/parse-events.c | 5 ++++- tools/perf/util/parse-events.y | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 9c6c4475524b9..bb08149179e40 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -246,7 +246,7 @@ $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-flex.h: util/parse- $(OUTPUT)util/parse-events-bison.c $(OUTPUT)util/parse-events-bison.h: util/parse-events.y $(call rule_mkdir) - $(Q)$(call echo-cmd,bison)$(BISON) -v $< -d $(PARSER_DEBUG_BISON) $(BISON_FILE_PREFIX_MAP) \ + $(Q)$(call echo-cmd,bison)$(BISON) -v $< -d $(PARSER_DEBUG_BISON) $(BISON_FILE_PREFIX_MAP) $(BISON_FALLBACK_FLAGS) \ -o $(OUTPUT)util/parse-events-bison.c -p parse_events_ $(OUTPUT)util/expr-flex.c $(OUTPUT)util/expr-flex.h: util/expr.l $(OUTPUT)util/expr-bison.c diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 75778d5be5b64..83adb0c2a6bcf 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1973,8 +1973,11 @@ int parse_events_name(struct list_head *list, const char *name) struct evsel *evsel; __evlist__for_each_entry(list, evsel) { - if (!evsel->name) + if (!evsel->name) { evsel->name = strdup(name); + if (!evsel->name) + return -ENOMEM; + } } return 0; diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index b09a5fa921445..3ee351768433e 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -263,7 +263,7 @@ PE_EVENT_NAME event_def free($1); if (err) { free_list_evsel($2); - YYABORT; + YYNOMEM; } $$ = $2; } -- GitLab From a7a3252dad354a9e5c173156dab959e4019b9467 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 27 Jun 2023 11:10:24 -0700 Subject: [PATCH 0533/3445] perf parse-events: Separate YYABORT and YYNOMEM cases Split cases in event_pmu for greater accuracy. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: bpf@vger.kernel.org Link: https://lore.kernel.org/r/20230627181030.95608-8-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.y | 45 ++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 3ee351768433e..d22866b97b761 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -283,37 +283,42 @@ event_pmu: PE_NAME opt_pmu_config { struct parse_events_state *parse_state = _parse_state; - struct parse_events_error *error = parse_state->error; struct list_head *list = NULL, *orig_terms = NULL, *terms= NULL; + struct parse_events_error *error = parse_state->error; char *pattern = NULL; -#define CLEANUP_YYABORT \ +#define CLEANUP \ do { \ parse_events_terms__delete($2); \ parse_events_terms__delete(orig_terms); \ free(list); \ free($1); \ free(pattern); \ - YYABORT; \ } while(0) - if (parse_events_copy_term_list($2, &orig_terms)) - CLEANUP_YYABORT; - if (error) error->idx = @1.first_column; + if (parse_events_copy_term_list($2, &orig_terms)) { + CLEANUP; + YYNOMEM; + } + list = alloc_list(); - if (!list) - CLEANUP_YYABORT; + if (!list) { + CLEANUP; + YYNOMEM; + } /* Attempt to add to list assuming $1 is a PMU name. */ if (parse_events_add_pmu(parse_state, list, $1, $2, /*auto_merge_stats=*/false)) { struct perf_pmu *pmu = NULL; int ok = 0; /* Failure to add, try wildcard expansion of $1 as a PMU name. */ - if (asprintf(&pattern, "%s*", $1) < 0) - CLEANUP_YYABORT; + if (asprintf(&pattern, "%s*", $1) < 0) { + CLEANUP; + YYNOMEM; + } while ((pmu = perf_pmus__scan(pmu)) != NULL) { char *name = pmu->name; @@ -328,8 +333,10 @@ PE_NAME opt_pmu_config !perf_pmu__match(pattern, pmu->alias_name, $1)) { bool auto_merge_stats = perf_pmu__auto_merge_stats(pmu); - if (parse_events_copy_term_list(orig_terms, &terms)) - CLEANUP_YYABORT; + if (parse_events_copy_term_list(orig_terms, &terms)) { + CLEANUP; + YYNOMEM; + } if (!parse_events_add_pmu(parse_state, list, pmu->name, terms, auto_merge_stats)) { ok++; @@ -345,15 +352,15 @@ PE_NAME opt_pmu_config ok = !parse_events_multi_pmu_add(parse_state, $1, $2, &list); $2 = NULL; } - if (!ok) - CLEANUP_YYABORT; + if (!ok) { + CLEANUP; + YYABORT; + } } - parse_events_terms__delete($2); - parse_events_terms__delete(orig_terms); - free(pattern); - free($1); $$ = list; -#undef CLEANUP_YYABORT + list = NULL; + CLEANUP; +#undef CLEANUP } | PE_NAME sep_dc -- GitLab From 77cdd787fc45e3426b8e0b5038b85c276540dfb4 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 27 Jun 2023 11:10:25 -0700 Subject: [PATCH 0534/3445] perf parse-events: Move instances of YYABORT to YYNOMEM Migration to improve error reporting as YYABORT cases should carry event parsing errors. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: bpf@vger.kernel.org Link: https://lore.kernel.org/r/20230627181030.95608-9-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.y | 58 +++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index d22866b97b761..eaf43bd8fe3fc 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -390,7 +390,8 @@ value_sym '/' event_config '/' bool wildcard = (type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE); list = alloc_list(); - ABORT_ON(!list); + if (!list) + YYNOMEM; err = parse_events_add_numeric(_parse_state, list, type, config, $3, wildcard); parse_events_terms__delete($3); if (err) { @@ -408,7 +409,8 @@ value_sym sep_slash_slash_dc bool wildcard = (type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE); list = alloc_list(); - ABORT_ON(!list); + if (!list) + YYNOMEM; ABORT_ON(parse_events_add_numeric(_parse_state, list, type, config, /*head_config=*/NULL, wildcard)); $$ = list; @@ -419,7 +421,8 @@ PE_VALUE_SYM_TOOL sep_slash_slash_dc struct list_head *list; list = alloc_list(); - ABORT_ON(!list); + if (!list) + YYNOMEM; ABORT_ON(parse_events_add_tool(_parse_state, list, $1)); $$ = list; } @@ -432,7 +435,9 @@ PE_LEGACY_CACHE opt_event_config int err; list = alloc_list(); - ABORT_ON(!list); + if (!list) + YYNOMEM; + err = parse_events_add_cache(list, &parse_state->idx, $1, parse_state, $2); parse_events_terms__delete($2); @@ -451,7 +456,9 @@ PE_PREFIX_MEM PE_VALUE PE_BP_SLASH PE_VALUE PE_BP_COLON PE_MODIFIER_BP opt_event int err; list = alloc_list(); - ABORT_ON(!list); + if (!list) + YYNOMEM; + err = parse_events_add_breakpoint(_parse_state, list, $2, $6, $4, $7); parse_events_terms__delete($7); @@ -469,7 +476,9 @@ PE_PREFIX_MEM PE_VALUE PE_BP_SLASH PE_VALUE opt_event_config int err; list = alloc_list(); - ABORT_ON(!list); + if (!list) + YYNOMEM; + err = parse_events_add_breakpoint(_parse_state, list, $2, NULL, $4, $5); parse_events_terms__delete($5); @@ -486,7 +495,9 @@ PE_PREFIX_MEM PE_VALUE PE_BP_COLON PE_MODIFIER_BP opt_event_config int err; list = alloc_list(); - ABORT_ON(!list); + if (!list) + YYNOMEM; + err = parse_events_add_breakpoint(_parse_state, list, $2, $4, 0, $5); parse_events_terms__delete($5); @@ -504,7 +515,8 @@ PE_PREFIX_MEM PE_VALUE opt_event_config int err; list = alloc_list(); - ABORT_ON(!list); + if (!list) + YYNOMEM; err = parse_events_add_breakpoint(_parse_state, list, $2, NULL, 0, $3); parse_events_terms__delete($3); @@ -524,7 +536,8 @@ tracepoint_name opt_event_config int err; list = alloc_list(); - ABORT_ON(!list); + if (!list) + YYNOMEM; if (error) error->idx = @1.first_column; @@ -556,7 +569,8 @@ PE_VALUE ':' PE_VALUE opt_event_config int err; list = alloc_list(); - ABORT_ON(!list); + if (!list) + YYNOMEM; err = parse_events_add_numeric(_parse_state, list, (u32)$1, $3, $4, /*wildcard=*/false); parse_events_terms__delete($4); @@ -575,7 +589,8 @@ PE_RAW opt_event_config u64 num; list = alloc_list(); - ABORT_ON(!list); + if (!list) + YYNOMEM; errno = 0; num = strtoull($1 + 1, NULL, 16); ABORT_ON(errno); @@ -598,7 +613,8 @@ PE_BPF_OBJECT opt_event_config int err; list = alloc_list(); - ABORT_ON(!list); + if (!list) + YYNOMEM; err = parse_events_load_bpf(parse_state, list, $1, false, $2); parse_events_terms__delete($2); free($1); @@ -615,7 +631,8 @@ PE_BPF_SOURCE opt_event_config int err; list = alloc_list(); - ABORT_ON(!list); + if (!list) + YYNOMEM; err = parse_events_load_bpf(_parse_state, list, $1, true, $2); parse_events_terms__delete($2); if (err) { @@ -680,7 +697,8 @@ event_term struct list_head *head = malloc(sizeof(*head)); struct parse_events_term *term = $1; - ABORT_ON(!head); + if (!head) + YYNOMEM; INIT_LIST_HEAD(head); list_add_tail(&term->list, head); $$ = head; @@ -857,7 +875,8 @@ PE_DRV_CFG_TERM struct parse_events_term *term; char *config = strdup($1); - ABORT_ON(!config); + if (!config) + YYNOMEM; if (parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_DRV_CFG, config, $1, &@1, NULL)) { free($1); @@ -888,7 +907,8 @@ array_terms ',' array_term new_array.ranges = realloc($1.ranges, sizeof(new_array.ranges[0]) * new_array.nr_ranges); - ABORT_ON(!new_array.ranges); + if (!new_array.ranges) + YYNOMEM; memcpy(&new_array.ranges[$1.nr_ranges], $3.ranges, $3.nr_ranges * sizeof(new_array.ranges[0])); free($3.ranges); @@ -904,7 +924,8 @@ PE_VALUE array.nr_ranges = 1; array.ranges = malloc(sizeof(array.ranges[0])); - ABORT_ON(!array.ranges); + if (!array.ranges) + YYNOMEM; array.ranges[0].start = $1; array.ranges[0].length = 1; $$ = array; @@ -917,7 +938,8 @@ PE_VALUE PE_ARRAY_RANGE PE_VALUE ABORT_ON($3 < $1); array.nr_ranges = 1; array.ranges = malloc(sizeof(array.ranges[0])); - ABORT_ON(!array.ranges); + if (!array.ranges) + YYNOMEM; array.ranges[0].start = $1; array.ranges[0].length = $3 - $1 + 1; $$ = array; -- GitLab From b52cb995f1a559bc6e1a7cdc0ed0375503528541 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 27 Jun 2023 11:10:26 -0700 Subject: [PATCH 0535/3445] perf parse-events: Separate ENOMEM memory handling Add PE_ABORT that will YYNOMEM or YYABORT accordingly. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: bpf@vger.kernel.org Link: https://lore.kernel.org/r/20230627181030.95608-10-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.y | 134 ++++++++++++++++++++------------- 1 file changed, 82 insertions(+), 52 deletions(-) diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index eaf43bd8fe3fc..f090a85c45180 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -28,6 +28,13 @@ do { \ YYABORT; \ } while (0) +#define PE_ABORT(val) \ +do { \ + if (val == -ENOMEM) \ + YYNOMEM; \ + YYABORT; \ +} while (0) + static struct list_head* alloc_list(void) { struct list_head *list; @@ -371,7 +378,7 @@ PE_NAME sep_dc err = parse_events_multi_pmu_add(_parse_state, $1, NULL, &list); free($1); if (err < 0) - YYABORT; + PE_ABORT(err); $$ = list; } @@ -396,7 +403,7 @@ value_sym '/' event_config '/' parse_events_terms__delete($3); if (err) { free_list_evsel(list); - YYABORT; + PE_ABORT(err); } $$ = list; } @@ -407,23 +414,28 @@ value_sym sep_slash_slash_dc int type = $1 >> 16; int config = $1 & 255; bool wildcard = (type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE); + int err; list = alloc_list(); if (!list) YYNOMEM; - ABORT_ON(parse_events_add_numeric(_parse_state, list, type, config, - /*head_config=*/NULL, wildcard)); + err = parse_events_add_numeric(_parse_state, list, type, config, /*head_config=*/NULL, wildcard); + if (err) + PE_ABORT(err); $$ = list; } | PE_VALUE_SYM_TOOL sep_slash_slash_dc { struct list_head *list; + int err; list = alloc_list(); if (!list) YYNOMEM; - ABORT_ON(parse_events_add_tool(_parse_state, list, $1)); + err = parse_events_add_tool(_parse_state, list, $1); + if (err) + YYNOMEM; $$ = list; } @@ -444,7 +456,7 @@ PE_LEGACY_CACHE opt_event_config free($1); if (err) { free_list_evsel(list); - YYABORT; + PE_ABORT(err); } $$ = list; } @@ -465,7 +477,7 @@ PE_PREFIX_MEM PE_VALUE PE_BP_SLASH PE_VALUE PE_BP_COLON PE_MODIFIER_BP opt_event free($6); if (err) { free(list); - YYABORT; + PE_ABORT(err); } $$ = list; } @@ -484,7 +496,7 @@ PE_PREFIX_MEM PE_VALUE PE_BP_SLASH PE_VALUE opt_event_config parse_events_terms__delete($5); if (err) { free(list); - YYABORT; + PE_ABORT(err); } $$ = list; } @@ -504,7 +516,7 @@ PE_PREFIX_MEM PE_VALUE PE_BP_COLON PE_MODIFIER_BP opt_event_config free($4); if (err) { free(list); - YYABORT; + PE_ABORT(err); } $$ = list; } @@ -522,7 +534,7 @@ PE_PREFIX_MEM PE_VALUE opt_event_config parse_events_terms__delete($3); if (err) { free(list); - YYABORT; + PE_ABORT(err); } $$ = list; } @@ -549,7 +561,7 @@ tracepoint_name opt_event_config free($1.event); if (err) { free(list); - YYABORT; + PE_ABORT(err); } $$ = list; } @@ -576,7 +588,7 @@ PE_VALUE ':' PE_VALUE opt_event_config parse_events_terms__delete($4); if (err) { free(list); - YYABORT; + PE_ABORT(err); } $$ = list; } @@ -600,7 +612,7 @@ PE_RAW opt_event_config parse_events_terms__delete($2); if (err) { free(list); - YYABORT; + PE_ABORT(err); } $$ = list; } @@ -620,7 +632,7 @@ PE_BPF_OBJECT opt_event_config free($1); if (err) { free(list); - YYABORT; + PE_ABORT(err); } $$ = list; } @@ -637,7 +649,7 @@ PE_BPF_SOURCE opt_event_config parse_events_terms__delete($2); if (err) { free(list); - YYABORT; + PE_ABORT(err); } $$ = list; } @@ -712,11 +724,12 @@ event_term: PE_RAW { struct parse_events_term *term; + int err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_RAW, + strdup("raw"), $1, &@1, &@1); - if (parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_RAW, - strdup("raw"), $1, &@1, &@1)) { + if (err) { free($1); - YYABORT; + PE_ABORT(err); } $$ = term; } @@ -724,12 +737,12 @@ PE_RAW name_or_raw '=' name_or_legacy { struct parse_events_term *term; + int err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER, $1, $3, &@1, &@3); - if (parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER, - $1, $3, &@1, &@3)) { + if (err) { free($1); free($3); - YYABORT; + PE_ABORT(err); } $$ = term; } @@ -737,11 +750,12 @@ name_or_raw '=' name_or_legacy name_or_raw '=' PE_VALUE { struct parse_events_term *term; + int err = parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, + $1, $3, false, &@1, &@3); - if (parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, - $1, $3, false, &@1, &@3)) { + if (err) { free($1); - YYABORT; + PE_ABORT(err); } $$ = term; } @@ -749,12 +763,13 @@ name_or_raw '=' PE_VALUE name_or_raw '=' PE_TERM_HW { struct parse_events_term *term; + int err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER, + $1, $3.str, &@1, &@3); - if (parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER, - $1, $3.str, &@1, &@3)) { + if (err) { free($1); free($3.str); - YYABORT; + PE_ABORT(err); } $$ = term; } @@ -762,11 +777,12 @@ name_or_raw '=' PE_TERM_HW PE_LEGACY_CACHE { struct parse_events_term *term; + int err = parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE, + $1, 1, true, &@1, NULL); - if (parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE, - $1, 1, true, &@1, NULL)) { + if (err) { free($1); - YYABORT; + PE_ABORT(err); } $$ = term; } @@ -774,11 +790,12 @@ PE_LEGACY_CACHE PE_NAME { struct parse_events_term *term; + int err = parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, + $1, 1, true, &@1, NULL); - if (parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, - $1, 1, true, &@1, NULL)) { + if (err) { free($1); - YYABORT; + PE_ABORT(err); } $$ = term; } @@ -786,11 +803,12 @@ PE_NAME PE_TERM_HW { struct parse_events_term *term; + int err = parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_HARDWARE, + $1.str, $1.num & 255, false, &@1, NULL); - if (parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_HARDWARE, - $1.str, $1.num & 255, false, &@1, NULL)) { + if (err) { free($1.str); - YYABORT; + PE_ABORT(err); } $$ = term; } @@ -798,10 +816,11 @@ PE_TERM_HW PE_TERM '=' name_or_legacy { struct parse_events_term *term; + int err = parse_events_term__str(&term, (int)$1, NULL, $3, &@1, &@3); - if (parse_events_term__str(&term, (int)$1, NULL, $3, &@1, &@3)) { + if (err) { free($3); - YYABORT; + PE_ABORT(err); } $$ = term; } @@ -809,10 +828,11 @@ PE_TERM '=' name_or_legacy PE_TERM '=' PE_TERM_HW { struct parse_events_term *term; + int err = parse_events_term__str(&term, (int)$1, NULL, $3.str, &@1, &@3); - if (parse_events_term__str(&term, (int)$1, NULL, $3.str, &@1, &@3)) { + if (err) { free($3.str); - YYABORT; + PE_ABORT(err); } $$ = term; } @@ -820,37 +840,46 @@ PE_TERM '=' PE_TERM_HW PE_TERM '=' PE_TERM { struct parse_events_term *term; + int err = parse_events_term__term(&term, (int)$1, (int)$3, &@1, &@3); + + if (err) + PE_ABORT(err); - ABORT_ON(parse_events_term__term(&term, (int)$1, (int)$3, &@1, &@3)); $$ = term; } | PE_TERM '=' PE_VALUE { struct parse_events_term *term; + int err = parse_events_term__num(&term, (int)$1, NULL, $3, false, &@1, &@3); + + if (err) + PE_ABORT(err); - ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, $3, false, &@1, &@3)); $$ = term; } | PE_TERM { struct parse_events_term *term; + int err = parse_events_term__num(&term, (int)$1, NULL, 1, true, &@1, NULL); + + if (err) + PE_ABORT(err); - ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, 1, true, &@1, NULL)); $$ = term; } | name_or_raw array '=' name_or_legacy { struct parse_events_term *term; + int err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER, $1, $4, &@1, &@4); - if (parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER, - $1, $4, &@1, &@4)) { + if (err) { free($1); free($4); free($2.ranges); - YYABORT; + PE_ABORT(err); } term->array = $2; $$ = term; @@ -859,12 +888,12 @@ name_or_raw array '=' name_or_legacy name_or_raw array '=' PE_VALUE { struct parse_events_term *term; + int err = parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, $1, $4, false, &@1, &@4); - if (parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, - $1, $4, false, &@1, &@4)) { + if (err) { free($1); free($2.ranges); - YYABORT; + PE_ABORT(err); } term->array = $2; $$ = term; @@ -874,14 +903,15 @@ PE_DRV_CFG_TERM { struct parse_events_term *term; char *config = strdup($1); + int err; if (!config) YYNOMEM; - if (parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_DRV_CFG, - config, $1, &@1, NULL)) { + err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_DRV_CFG, config, $1, &@1, NULL); + if (err) { free($1); free(config); - YYABORT; + PE_ABORT(err); } $$ = term; } -- GitLab From b30d4f0b695428f513c561eeaea52e042ef48550 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 27 Jun 2023 11:10:27 -0700 Subject: [PATCH 0536/3445] perf parse-events: Additional error reporting When no events or PMUs match report an error for event_pmu: Before: ``` $ perf stat -e 'asdfasdf' -a sleep 1 Run 'perf list' for a list of valid events Usage: perf stat [] [] -e, --event event selector. use 'perf list' to list available events ``` After: ``` $ perf stat -e 'asdfasdf' -a sleep 1 event syntax error: 'asdfasdf' \___ Bad event name Unabled to find PMU or event on a PMU of 'asdfasdf' Run 'perf list' for a list of valid events Usage: perf stat [] [] -e, --event event selector. use 'perf list' to list available events ``` Fixes the inadvertent removal when hybrid parsing was modified. Fixes: 70c90e4a6b2fbe77 ("perf parse-events: Avoid scanning PMUs before parsing") Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: bpf@vger.kernel.org Link: https://lore.kernel.org/r/20230627181030.95608-11-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.y | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index f090a85c45180..a636a7db6e6ff 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -291,7 +291,6 @@ PE_NAME opt_pmu_config { struct parse_events_state *parse_state = _parse_state; struct list_head *list = NULL, *orig_terms = NULL, *terms= NULL; - struct parse_events_error *error = parse_state->error; char *pattern = NULL; #define CLEANUP \ @@ -303,9 +302,6 @@ PE_NAME opt_pmu_config free(pattern); \ } while(0) - if (error) - error->idx = @1.first_column; - if (parse_events_copy_term_list($2, &orig_terms)) { CLEANUP; YYNOMEM; @@ -360,6 +356,14 @@ PE_NAME opt_pmu_config $2 = NULL; } if (!ok) { + struct parse_events_error *error = parse_state->error; + char *help; + + if (asprintf(&help, "Unabled to find PMU or event on a PMU of '%s'", $1) < 0) + help = NULL; + parse_events_error__handle(error, @1.first_column, + strdup("Bad event or PMU"), + help); CLEANUP; YYABORT; } @@ -376,9 +380,18 @@ PE_NAME sep_dc int err; err = parse_events_multi_pmu_add(_parse_state, $1, NULL, &list); - free($1); - if (err < 0) + if (err < 0) { + struct parse_events_state *parse_state = _parse_state; + struct parse_events_error *error = parse_state->error; + char *help; + + if (asprintf(&help, "Unabled to find PMU or event on a PMU of '%s'", $1) < 0) + help = NULL; + parse_events_error__handle(error, @1.first_column, strdup("Bad event name"), help); + free($1); PE_ABORT(err); + } + free($1); $$ = list; } -- GitLab From d81fa63b09fbd8b6ae5761164ed75f9ccf005893 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 27 Jun 2023 11:10:28 -0700 Subject: [PATCH 0537/3445] perf parse-events: Populate error column for BPF/tracepoint events Follow convention from parse_events_terms__num/str and pass the YYLTYPE for the location. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: bpf@vger.kernel.org Link: https://lore.kernel.org/r/20230627181030.95608-12-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/bpf.c | 2 +- tools/perf/util/parse-events.c | 80 ++++++++++++++++++++-------------- tools/perf/util/parse-events.h | 8 ++-- tools/perf/util/parse-events.y | 6 +-- 4 files changed, 57 insertions(+), 39 deletions(-) diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c index 8beb460660343..31796f2a80f47 100644 --- a/tools/perf/tests/bpf.c +++ b/tools/perf/tests/bpf.c @@ -124,7 +124,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void), parse_state.error = &parse_error; INIT_LIST_HEAD(&parse_state.list); - err = parse_events_load_bpf_obj(&parse_state, &parse_state.list, obj, NULL); + err = parse_events_load_bpf_obj(&parse_state, &parse_state.list, obj, NULL, NULL); parse_events_error__exit(&parse_error); if (err == -ENODATA) { pr_debug("Failed to add events selected by BPF, debuginfo package not installed\n"); diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 83adb0c2a6bcf..7c13b70e743c8 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -499,7 +499,7 @@ int parse_events_add_cache(struct list_head *list, int *idx, const char *name, #ifdef HAVE_LIBTRACEEVENT static void tracepoint_error(struct parse_events_error *e, int err, - const char *sys, const char *name) + const char *sys, const char *name, int column) { const char *str; char help[BUFSIZ]; @@ -526,18 +526,19 @@ static void tracepoint_error(struct parse_events_error *e, int err, } tracing_path__strerror_open_tp(err, help, sizeof(help), sys, name); - parse_events_error__handle(e, 0, strdup(str), strdup(help)); + parse_events_error__handle(e, column, strdup(str), strdup(help)); } static int add_tracepoint(struct list_head *list, int *idx, const char *sys_name, const char *evt_name, struct parse_events_error *err, - struct list_head *head_config) + struct list_head *head_config, void *loc_) { + YYLTYPE *loc = loc_; struct evsel *evsel = evsel__newtp_idx(sys_name, evt_name, (*idx)++); if (IS_ERR(evsel)) { - tracepoint_error(err, PTR_ERR(evsel), sys_name, evt_name); + tracepoint_error(err, PTR_ERR(evsel), sys_name, evt_name, loc->first_column); return PTR_ERR(evsel); } @@ -556,7 +557,7 @@ static int add_tracepoint(struct list_head *list, int *idx, static int add_tracepoint_multi_event(struct list_head *list, int *idx, const char *sys_name, const char *evt_name, struct parse_events_error *err, - struct list_head *head_config) + struct list_head *head_config, YYLTYPE *loc) { char *evt_path; struct dirent *evt_ent; @@ -565,13 +566,13 @@ static int add_tracepoint_multi_event(struct list_head *list, int *idx, evt_path = get_events_file(sys_name); if (!evt_path) { - tracepoint_error(err, errno, sys_name, evt_name); + tracepoint_error(err, errno, sys_name, evt_name, loc->first_column); return -1; } evt_dir = opendir(evt_path); if (!evt_dir) { put_events_file(evt_path); - tracepoint_error(err, errno, sys_name, evt_name); + tracepoint_error(err, errno, sys_name, evt_name, loc->first_column); return -1; } @@ -588,11 +589,11 @@ static int add_tracepoint_multi_event(struct list_head *list, int *idx, found++; ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name, - err, head_config); + err, head_config, loc); } if (!found) { - tracepoint_error(err, ENOENT, sys_name, evt_name); + tracepoint_error(err, ENOENT, sys_name, evt_name, loc->first_column); ret = -1; } @@ -604,19 +605,19 @@ static int add_tracepoint_multi_event(struct list_head *list, int *idx, static int add_tracepoint_event(struct list_head *list, int *idx, const char *sys_name, const char *evt_name, struct parse_events_error *err, - struct list_head *head_config) + struct list_head *head_config, YYLTYPE *loc) { return strpbrk(evt_name, "*?") ? - add_tracepoint_multi_event(list, idx, sys_name, evt_name, - err, head_config) : - add_tracepoint(list, idx, sys_name, evt_name, - err, head_config); + add_tracepoint_multi_event(list, idx, sys_name, evt_name, + err, head_config, loc) : + add_tracepoint(list, idx, sys_name, evt_name, + err, head_config, loc); } static int add_tracepoint_multi_sys(struct list_head *list, int *idx, const char *sys_name, const char *evt_name, struct parse_events_error *err, - struct list_head *head_config) + struct list_head *head_config, YYLTYPE *loc) { struct dirent *events_ent; DIR *events_dir; @@ -624,7 +625,7 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx, events_dir = tracing_events__opendir(); if (!events_dir) { - tracepoint_error(err, errno, sys_name, evt_name); + tracepoint_error(err, errno, sys_name, evt_name, loc->first_column); return -1; } @@ -640,7 +641,7 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx, continue; ret = add_tracepoint_event(list, idx, events_ent->d_name, - evt_name, err, head_config); + evt_name, err, head_config, loc); } closedir(events_dir); @@ -653,6 +654,7 @@ struct __add_bpf_event_param { struct parse_events_state *parse_state; struct list_head *list; struct list_head *head_config; + YYLTYPE *loc; }; static int add_bpf_event(const char *group, const char *event, int fd, struct bpf_object *obj, @@ -679,7 +681,7 @@ static int add_bpf_event(const char *group, const char *event, int fd, struct bp err = parse_events_add_tracepoint(&new_evsels, &parse_state->idx, group, event, parse_state->error, - param->head_config); + param->head_config, param->loc); if (err) { struct evsel *evsel, *tmp; @@ -706,12 +708,14 @@ static int add_bpf_event(const char *group, const char *event, int fd, struct bp int parse_events_load_bpf_obj(struct parse_events_state *parse_state, struct list_head *list, struct bpf_object *obj, - struct list_head *head_config) + struct list_head *head_config, + void *loc) { int err; char errbuf[BUFSIZ]; - struct __add_bpf_event_param param = {parse_state, list, head_config}; + struct __add_bpf_event_param param = {parse_state, list, head_config, loc}; static bool registered_unprobe_atexit = false; + YYLTYPE test_loc = {.first_column = -1}; if (IS_ERR(obj) || !obj) { snprintf(errbuf, sizeof(errbuf), @@ -742,6 +746,9 @@ int parse_events_load_bpf_obj(struct parse_events_state *parse_state, goto errout; } + if (!param.loc) + param.loc = &test_loc; + err = bpf__foreach_event(obj, add_bpf_event, ¶m); if (err) { snprintf(errbuf, sizeof(errbuf), @@ -751,7 +758,7 @@ int parse_events_load_bpf_obj(struct parse_events_state *parse_state, return 0; errout: - parse_events_error__handle(parse_state->error, 0, + parse_events_error__handle(parse_state->error, param.loc->first_column, strdup(errbuf), strdup("(add -v to see detail)")); return err; } @@ -839,11 +846,13 @@ int parse_events_load_bpf(struct parse_events_state *parse_state, struct list_head *list, char *bpf_file_name, bool source, - struct list_head *head_config) + struct list_head *head_config, + void *loc_) { int err; struct bpf_object *obj; LIST_HEAD(obj_head_config); + YYLTYPE *loc = loc_; if (head_config) split_bpf_config_terms(head_config, &obj_head_config); @@ -863,12 +872,12 @@ int parse_events_load_bpf(struct parse_events_state *parse_state, -err, errbuf, sizeof(errbuf)); - parse_events_error__handle(parse_state->error, 0, + parse_events_error__handle(parse_state->error, loc->first_column, strdup(errbuf), strdup("(add -v to see detail)")); return err; } - err = parse_events_load_bpf_obj(parse_state, list, obj, head_config); + err = parse_events_load_bpf_obj(parse_state, list, obj, head_config, loc); if (err) return err; err = parse_events_config_bpf(parse_state, obj, &obj_head_config); @@ -885,9 +894,12 @@ int parse_events_load_bpf(struct parse_events_state *parse_state, int parse_events_load_bpf_obj(struct parse_events_state *parse_state, struct list_head *list __maybe_unused, struct bpf_object *obj __maybe_unused, - struct list_head *head_config __maybe_unused) + struct list_head *head_config __maybe_unused, + void *loc_) { - parse_events_error__handle(parse_state->error, 0, + YYLTYPE *loc = loc_; + + parse_events_error__handle(parse_state->error, loc->first_column, strdup("BPF support is not compiled"), strdup("Make sure libbpf-devel is available at build time.")); return -ENOTSUP; @@ -897,9 +909,12 @@ int parse_events_load_bpf(struct parse_events_state *parse_state, struct list_head *list __maybe_unused, char *bpf_file_name __maybe_unused, bool source __maybe_unused, - struct list_head *head_config __maybe_unused) + struct list_head *head_config __maybe_unused, + void *loc_) { - parse_events_error__handle(parse_state->error, 0, + YYLTYPE *loc = loc_; + + parse_events_error__handle(parse_state->error, loc->first_column, strdup("BPF support is not compiled"), strdup("Make sure libbpf-devel is available at build time.")); return -ENOTSUP; @@ -1441,8 +1456,9 @@ static int get_config_chgs(struct perf_pmu *pmu, struct list_head *head_config, int parse_events_add_tracepoint(struct list_head *list, int *idx, const char *sys, const char *event, struct parse_events_error *err, - struct list_head *head_config) + struct list_head *head_config, void *loc_) { + YYLTYPE *loc = loc_; #ifdef HAVE_LIBTRACEEVENT if (head_config) { struct perf_event_attr attr; @@ -1454,17 +1470,17 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx, if (strpbrk(sys, "*?")) return add_tracepoint_multi_sys(list, idx, sys, event, - err, head_config); + err, head_config, loc); else return add_tracepoint_event(list, idx, sys, event, - err, head_config); + err, head_config, loc); #else (void)list; (void)idx; (void)sys; (void)event; (void)head_config; - parse_events_error__handle(err, 0, strdup("unsupported tracepoint"), + parse_events_error__handle(err, loc->first_column, strdup("unsupported tracepoint"), strdup("libtraceevent is necessary for tracepoint support")); return -1; #endif diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index b37e5ee193a8f..cabbe70adb827 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -169,18 +169,20 @@ int parse_events_name(struct list_head *list, const char *name); int parse_events_add_tracepoint(struct list_head *list, int *idx, const char *sys, const char *event, struct parse_events_error *error, - struct list_head *head_config); + struct list_head *head_config, void *loc); int parse_events_load_bpf(struct parse_events_state *parse_state, struct list_head *list, char *bpf_file_name, bool source, - struct list_head *head_config); + struct list_head *head_config, + void *loc); /* Provide this function for perf test */ struct bpf_object; int parse_events_load_bpf_obj(struct parse_events_state *parse_state, struct list_head *list, struct bpf_object *obj, - struct list_head *head_config); + struct list_head *head_config, + void *loc); int parse_events_add_numeric(struct parse_events_state *parse_state, struct list_head *list, u32 type, u64 config, diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index a636a7db6e6ff..50f5b819de377 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -567,7 +567,7 @@ tracepoint_name opt_event_config error->idx = @1.first_column; err = parse_events_add_tracepoint(list, &parse_state->idx, $1.sys, $1.event, - error, $2); + error, $2, &@1); parse_events_terms__delete($2); free($1.sys); @@ -640,7 +640,7 @@ PE_BPF_OBJECT opt_event_config list = alloc_list(); if (!list) YYNOMEM; - err = parse_events_load_bpf(parse_state, list, $1, false, $2); + err = parse_events_load_bpf(parse_state, list, $1, false, $2, &@1); parse_events_terms__delete($2); free($1); if (err) { @@ -658,7 +658,7 @@ PE_BPF_SOURCE opt_event_config list = alloc_list(); if (!list) YYNOMEM; - err = parse_events_load_bpf(_parse_state, list, $1, true, $2); + err = parse_events_load_bpf(_parse_state, list, $1, true, $2, &@1); parse_events_terms__delete($2); if (err) { free(list); -- GitLab From 81a4e31f8c4a50bc5c5f49a1e2e4a295edd57719 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 27 Jun 2023 11:10:29 -0700 Subject: [PATCH 0538/3445] perf parse-events: Improve location for add pmu Improve the location for add PMU for cases when PMUs aren't found. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: bpf@vger.kernel.org Link: https://lore.kernel.org/r/20230627181030.95608-13-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 12 +++++++----- tools/perf/util/parse-events.h | 4 ++-- tools/perf/util/parse-events.y | 8 ++++---- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 7c13b70e743c8..926d3ac97324c 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1575,13 +1575,14 @@ static bool config_term_percore(struct list_head *config_terms) int parse_events_add_pmu(struct parse_events_state *parse_state, struct list_head *list, char *name, struct list_head *head_config, - bool auto_merge_stats) + bool auto_merge_stats, void *loc_) { struct perf_event_attr attr; struct perf_pmu_info info; struct perf_pmu *pmu; struct evsel *evsel; struct parse_events_error *err = parse_state->error; + YYLTYPE *loc = loc_; LIST_HEAD(config_terms); pmu = parse_state->fake_pmu ?: perf_pmus__find(name); @@ -1605,7 +1606,7 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, if (asprintf(&err_str, "Cannot find PMU `%s'. Missing kernel support?", name) >= 0) - parse_events_error__handle(err, 0, err_str, NULL); + parse_events_error__handle(err, loc->first_column, err_str, NULL); return -EINVAL; } if (head_config) @@ -1691,12 +1692,13 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, int parse_events_multi_pmu_add(struct parse_events_state *parse_state, char *str, struct list_head *head, - struct list_head **listp) + struct list_head **listp, void *loc_) { struct parse_events_term *term; struct list_head *list = NULL; struct list_head *orig_head = NULL; struct perf_pmu *pmu = NULL; + YYLTYPE *loc = loc_; int ok = 0; char *config; @@ -1743,7 +1745,7 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state, parse_events_copy_term_list(head, &orig_head); if (!parse_events_add_pmu(parse_state, list, pmu->name, orig_head, - auto_merge_stats)) { + auto_merge_stats, loc)) { pr_debug("%s -> %s/%s/\n", str, pmu->name, alias->str); parse_state->wild_card_pmus = true; @@ -1756,7 +1758,7 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state, if (parse_state->fake_pmu) { if (!parse_events_add_pmu(parse_state, list, str, head, - /*auto_merge_stats=*/true)) { + /*auto_merge_stats=*/true, loc)) { pr_debug("%s -> %s/%s/\n", str, "fake_pmu", str); ok++; } diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index cabbe70adb827..e59b338058860 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -202,7 +202,7 @@ int parse_events_add_breakpoint(struct parse_events_state *parse_state, int parse_events_add_pmu(struct parse_events_state *parse_state, struct list_head *list, char *name, struct list_head *head_config, - bool auto_merge_stats); + bool auto_merge_stats, void *loc); struct evsel *parse_events__add_event(int idx, struct perf_event_attr *attr, const char *name, const char *metric_id, @@ -211,7 +211,7 @@ struct evsel *parse_events__add_event(int idx, struct perf_event_attr *attr, int parse_events_multi_pmu_add(struct parse_events_state *parse_state, char *str, struct list_head *head_config, - struct list_head **listp); + struct list_head **listp, void *loc); int parse_events_copy_term_list(struct list_head *old, struct list_head **new); diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 50f5b819de377..8446467524628 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -313,7 +313,7 @@ PE_NAME opt_pmu_config YYNOMEM; } /* Attempt to add to list assuming $1 is a PMU name. */ - if (parse_events_add_pmu(parse_state, list, $1, $2, /*auto_merge_stats=*/false)) { + if (parse_events_add_pmu(parse_state, list, $1, $2, /*auto_merge_stats=*/false, &@1)) { struct perf_pmu *pmu = NULL; int ok = 0; @@ -341,7 +341,7 @@ PE_NAME opt_pmu_config YYNOMEM; } if (!parse_events_add_pmu(parse_state, list, pmu->name, terms, - auto_merge_stats)) { + auto_merge_stats, &@1)) { ok++; parse_state->wild_card_pmus = true; } @@ -352,7 +352,7 @@ PE_NAME opt_pmu_config if (!ok) { /* Failure to add, assume $1 is an event name. */ zfree(&list); - ok = !parse_events_multi_pmu_add(parse_state, $1, $2, &list); + ok = !parse_events_multi_pmu_add(parse_state, $1, $2, &list, &@1); $2 = NULL; } if (!ok) { @@ -379,7 +379,7 @@ PE_NAME sep_dc struct list_head *list; int err; - err = parse_events_multi_pmu_add(_parse_state, $1, NULL, &list); + err = parse_events_multi_pmu_add(_parse_state, $1, NULL, &list, &@1); if (err < 0) { struct parse_events_state *parse_state = _parse_state; struct parse_events_error *error = parse_state->error; -- GitLab From 4c11adff675652759a0f0ad2194f4646b5463a42 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Tue, 27 Jun 2023 11:10:30 -0700 Subject: [PATCH 0539/3445] perf parse-events: Remove ABORT_ON Prefer informative messages rather than none with ABORT_ON. Document one failure mode and add an error message for another. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: bpf@vger.kernel.org Link: https://lore.kernel.org/r/20230627181030.95608-14-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.y | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 8446467524628..454577f7aff67 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -22,12 +22,6 @@ void parse_events_error(YYLTYPE *loc, void *parse_state, void *scanner, char const *msg); -#define ABORT_ON(val) \ -do { \ - if (val) \ - YYABORT; \ -} while (0) - #define PE_ABORT(val) \ do { \ if (val == -ENOMEM) \ @@ -618,7 +612,9 @@ PE_RAW opt_event_config YYNOMEM; errno = 0; num = strtoull($1 + 1, NULL, 16); - ABORT_ON(errno); + /* Given the lexer will only give [a-fA-F0-9]+ a failure here should be impossible. */ + if (errno) + YYABORT; free($1); err = parse_events_add_numeric(_parse_state, list, PERF_TYPE_RAW, num, $2, /*wildcard=*/false); @@ -978,7 +974,17 @@ PE_VALUE PE_ARRAY_RANGE PE_VALUE { struct parse_events_array array; - ABORT_ON($3 < $1); + if ($3 < $1) { + struct parse_events_state *parse_state = _parse_state; + struct parse_events_error *error = parse_state->error; + char *err_str; + + if (asprintf(&err_str, "Expected '%ld' to be less-than '%ld'", $3, $1) < 0) + err_str = NULL; + + parse_events_error__handle(error, @1.first_column, err_str, NULL); + YYABORT; + } array.nr_ranges = 1; array.ranges = malloc(sizeof(array.ranges[0])); if (!array.ranges) -- GitLab From f9dd531c5b82037f0f8f9ffc04ce0c09840fba2e Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 24 Jul 2023 17:19:28 -0700 Subject: [PATCH 0540/3445] perf symbols: Add kallsyms__get_symbol_start() The kallsyms__get_symbol_start() to get any symbol address from kallsyms. The existing kallsyms__get_function_start() only allows text symbols so create this to allow data symbols too. Signed-off-by: Namhyung Kim Acked-by: Adrian Hunter Acked-by: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20230725001929.368041-1-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 30 +++++++++++++++++++++++++++--- tools/perf/util/event.h | 2 ++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 4cbb092e0684c..923c0fb151222 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -93,8 +93,8 @@ struct process_symbol_args { u64 start; }; -static int find_symbol_cb(void *arg, const char *name, char type, - u64 start) +static int find_func_symbol_cb(void *arg, const char *name, char type, + u64 start) { struct process_symbol_args *args = arg; @@ -110,12 +110,36 @@ static int find_symbol_cb(void *arg, const char *name, char type, return 1; } +static int find_any_symbol_cb(void *arg, const char *name, + char type __maybe_unused, u64 start) +{ + struct process_symbol_args *args = arg; + + if (strcmp(name, args->name)) + return 0; + + args->start = start; + return 1; +} + int kallsyms__get_function_start(const char *kallsyms_filename, const char *symbol_name, u64 *addr) { struct process_symbol_args args = { .name = symbol_name, }; - if (kallsyms__parse(kallsyms_filename, &args, find_symbol_cb) <= 0) + if (kallsyms__parse(kallsyms_filename, &args, find_func_symbol_cb) <= 0) + return -1; + + *addr = args.start; + return 0; +} + +int kallsyms__get_symbol_start(const char *kallsyms_filename, + const char *symbol_name, u64 *addr) +{ + struct process_symbol_args args = { .name = symbol_name, }; + + if (kallsyms__parse(kallsyms_filename, &args, find_any_symbol_cb) <= 0) return -1; *addr = args.start; diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index de20e01c9d72a..d8bcee2e9b93b 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -360,6 +360,8 @@ size_t perf_event__fprintf(union perf_event *event, struct machine *machine, FIL int kallsyms__get_function_start(const char *kallsyms_filename, const char *symbol_name, u64 *addr); +int kallsyms__get_symbol_start(const char *kallsyms_filename, + const char *symbol_name, u64 *addr); void event_attr_init(struct perf_event_attr *attr); -- GitLab From 69a87a32f5cd8b262cb2195b045f96c63aede734 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 24 Jul 2023 17:19:29 -0700 Subject: [PATCH 0541/3445] perf machine: Include data symbols in the kernel map When 'perf record -d' is used, it needs data mmaps to symbolize global data. But it missed to collect kernel data maps so it cannot symbolize them. Instead of having a separate map, just increase the kernel map size to include the data section. Probably we can have a separate kernel map for data, but the current code assumes a single kernel map. So it'd require more changes in other places and looks error-prone. I decided not to go that way for now. Also it seems the kernel module size already includes the data section. For example, my system has the following. $ grep -e _stext -e _etext -e _edata /proc/kallsyms ffffffff99800000 T _stext ffffffff9a601ac8 T _etext ffffffff9b446a00 D _edata Size of the text section is (0x9a601ac8 - 0x99800000 = 0xe01ac8) and size including data section is (0x9b446a00 - 0x99800000 = 0x1c46a00). Before: $ perf record -d true $ perf report -D | grep MMAP | head -1 0 0 0x460 [0x60]: PERF_RECORD_MMAP -1/0: [0xffffffff99800000(0xe01ac8) @ 0xffffffff99800000]: x [kernel.kallsyms]_text ^^^^^^^^ here After: $ perf report -D | grep MMAP | head -1 0 0 0x460 [0x60]: PERF_RECORD_MMAP -1/0: [0xffffffff99800000(0x1c46a00) @ 0xffffffff99800000]: x [kernel.kallsyms]_text ^^^^^^^^^ Instead of just replacing it to _edata, try _edata first and then fall back to _etext just in case. Signed-off-by: Namhyung Kim Acked-by: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20230725001929.368041-2-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/machine.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 4e62843d51b7d..11de3ca8d4fa7 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -1216,7 +1216,9 @@ static int machine__get_running_kernel_start(struct machine *machine, *start = addr; - err = kallsyms__get_function_start(filename, "_etext", &addr); + err = kallsyms__get_symbol_start(filename, "_edata", &addr); + if (err) + err = kallsyms__get_function_start(filename, "_etext", &addr); if (!err) *end = addr; -- GitLab From 1e37201405590eac6491f9e677bd4064a92900e8 Mon Sep 17 00:00:00 2001 From: Xiu Jianfeng Date: Thu, 27 Jul 2023 10:50:01 +0000 Subject: [PATCH 0542/3445] perf doc: Fix typo in perf.data-file-format.txt The 'it' should be 'is' here, fix it. Signed-off-by: Xiu Jianfeng Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20230727105001.261420-1-xiujianfeng@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf.data-file-format.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/Documentation/perf.data-file-format.txt b/tools/perf/Documentation/perf.data-file-format.txt index 635ba043fd7d8..010a4edcd3849 100644 --- a/tools/perf/Documentation/perf.data-file-format.txt +++ b/tools/perf/Documentation/perf.data-file-format.txt @@ -43,7 +43,7 @@ struct perf_file_section { Flags section: -For each of the optional features a perf_file_section it placed after the data +For each of the optional features a perf_file_section is placed after the data section if the feature bit is set in the perf_header flags bitset. The respective perf_file_section points to the data of the additional header and defines its size. -- GitLab From 1699d3efe111e33e275ca7d4163c8b1470ba79b3 Mon Sep 17 00:00:00 2001 From: Anup Sharma Date: Fri, 21 Jul 2023 23:22:28 +0530 Subject: [PATCH 0543/3445] perf scripts python: Add initial script file with usage information Added necessary modules, including the Perf-Trace-Util library, and defines the required functions and variables for using perf script python. The perf_trace_context and Core modules for tracing and processing events has been also imported. Added usage information. Signed-off-by: Anup Sharma Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/f2f1a62f1cc69f44a5414da46a26a4cf124d2744.1689961706.git.anupnewsmail@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/scripts/python/gecko.py | 31 ++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 tools/perf/scripts/python/gecko.py diff --git a/tools/perf/scripts/python/gecko.py b/tools/perf/scripts/python/gecko.py new file mode 100644 index 0000000000000..7a62c1b411d93 --- /dev/null +++ b/tools/perf/scripts/python/gecko.py @@ -0,0 +1,31 @@ +# firefox-gecko-converter.py - Convert perf record output to Firefox's gecko profile format +# SPDX-License-Identifier: GPL-2.0 +# +# The script converts perf.data to Gecko Profile Format, +# which can be read by https://profiler.firefox.com/. +# +# Usage: +# +# perf record -a -g -F 99 sleep 60 +# perf script report gecko > output.json + +import os +import sys +from typing import Dict + +# Add the Perf-Trace-Util library to the Python path +sys.path.append(os.environ['PERF_EXEC_PATH'] + \ + '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') + +from perf_trace_context import * +from Core import * + +# Uses perf script python interface to parse each +# event and store the data in the thread builder. +def process_event(param_dict: Dict) -> None: + pass + +# Trace_end runs at the end and will be used to aggregate +# the data into the final json object and print it out to stdout. +def trace_end() -> None: + pass -- GitLab From 0a02e44cc2fe1657af1f2740cb9a1dcd8a9338cc Mon Sep 17 00:00:00 2001 From: Anup Sharma Date: Fri, 21 Jul 2023 23:22:56 +0530 Subject: [PATCH 0544/3445] perf scripts python: Extact necessary information from process event The script takes in a sample event dictionary(param_dict) and retrieves relevant data such as time stamp, PID, TID, and comm for each event. Also start time is defined as a global variable as it need to be passed to trace_end for gecko meta information field creation. Signed-off-by: Anup Sharma Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/19910fefcfe4be03cd5c2aa3fec11d3f86c0381b.1689961706.git.anupnewsmail@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/scripts/python/gecko.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tools/perf/scripts/python/gecko.py b/tools/perf/scripts/python/gecko.py index 7a62c1b411d93..a02b1e04ff52e 100644 --- a/tools/perf/scripts/python/gecko.py +++ b/tools/perf/scripts/python/gecko.py @@ -20,10 +20,22 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \ from perf_trace_context import * from Core import * +# start_time is intialiazed only once for the all event traces. +start_time = None + # Uses perf script python interface to parse each # event and store the data in the thread builder. def process_event(param_dict: Dict) -> None: - pass + global start_time + global tid_to_thread + time_stamp = (param_dict['sample']['time'] // 1000) / 1000 + pid = param_dict['sample']['pid'] + tid = param_dict['sample']['tid'] + comm = param_dict['comm'] + + # Start time is the time of the first sample + if not start_time: + start_time = time_stamp # Trace_end runs at the end and will be used to aggregate # the data into the final json object and print it out to stdout. -- GitLab From 5aacd7f08a3276f4fad729a600d51a1cc5d5191a Mon Sep 17 00:00:00 2001 From: Anup Sharma Date: Fri, 21 Jul 2023 23:23:19 +0530 Subject: [PATCH 0545/3445] perf scripts python: Add classes and conversion functions This commit introduces new classes and conversion functions to facilitate the representation of Gecko profile information. The new classes Frame, Stack, Sample, and Thread are added to handle specific components of the profile data, also link to the origin docs has been commented out. Additionally, Inside the Thread class _to_json_dict() method has been created that converts the current thread data into the corresponding format expected by the GeckoThread JSON schema, as per the Gecko profile format specification. Signed-off-by: Anup Sharma Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/ab7b40bd32df7101a6f8b4a3aa41570b63b831ac.1689961706.git.anupnewsmail@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/scripts/python/gecko.py | 133 ++++++++++++++++++++++++++++- 1 file changed, 132 insertions(+), 1 deletion(-) diff --git a/tools/perf/scripts/python/gecko.py b/tools/perf/scripts/python/gecko.py index a02b1e04ff52e..2cd5cd6e31e35 100644 --- a/tools/perf/scripts/python/gecko.py +++ b/tools/perf/scripts/python/gecko.py @@ -11,7 +11,8 @@ import os import sys -from typing import Dict +from dataclasses import dataclass, field +from typing import List, Dict, Optional, NamedTuple, Set, Tuple, Any # Add the Perf-Trace-Util library to the Python path sys.path.append(os.environ['PERF_EXEC_PATH'] + \ @@ -20,9 +21,139 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \ from perf_trace_context import * from Core import * +StringID = int +StackID = int +FrameID = int +CategoryID = int +Milliseconds = float + # start_time is intialiazed only once for the all event traces. start_time = None +# https://github.com/firefox-devtools/profiler/blob/53970305b51b9b472e26d7457fee1d66cd4e2737/src/types/gecko-profile.js#L156 +class Frame(NamedTuple): + string_id: StringID + relevantForJS: bool + innerWindowID: int + implementation: None + optimizations: None + line: None + column: None + category: CategoryID + subcategory: int + +# https://github.com/firefox-devtools/profiler/blob/53970305b51b9b472e26d7457fee1d66cd4e2737/src/types/gecko-profile.js#L216 +class Stack(NamedTuple): + prefix_id: Optional[StackID] + frame_id: FrameID + +# https://github.com/firefox-devtools/profiler/blob/53970305b51b9b472e26d7457fee1d66cd4e2737/src/types/gecko-profile.js#L90 +class Sample(NamedTuple): + stack_id: Optional[StackID] + time_ms: Milliseconds + responsiveness: int + +@dataclass +class Thread: + """A builder for a profile of the thread. + + Attributes: + comm: Thread command-line (name). + pid: process ID of containing process. + tid: thread ID. + samples: Timeline of profile samples. + frameTable: interned stack frame ID -> stack frame. + stringTable: interned string ID -> string. + stringMap: interned string -> string ID. + stackTable: interned stack ID -> stack. + stackMap: (stack prefix ID, leaf stack frame ID) -> interned Stack ID. + frameMap: Stack Frame string -> interned Frame ID. + comm: str + pid: int + tid: int + samples: List[Sample] = field(default_factory=list) + frameTable: List[Frame] = field(default_factory=list) + stringTable: List[str] = field(default_factory=list) + stringMap: Dict[str, int] = field(default_factory=dict) + stackTable: List[Stack] = field(default_factory=list) + stackMap: Dict[Tuple[Optional[int], int], int] = field(default_factory=dict) + frameMap: Dict[str, int] = field(default_factory=dict) + """ + comm: str + pid: int + tid: int + samples: List[Sample] = field(default_factory=list) + frameTable: List[Frame] = field(default_factory=list) + stringTable: List[str] = field(default_factory=list) + stringMap: Dict[str, int] = field(default_factory=dict) + stackTable: List[Stack] = field(default_factory=list) + stackMap: Dict[Tuple[Optional[int], int], int] = field(default_factory=dict) + frameMap: Dict[str, int] = field(default_factory=dict) + + def _to_json_dict(self) -> Dict: + """Converts current Thread to GeckoThread JSON format.""" + # Gecko profile format is row-oriented data as List[List], + # And a schema for interpreting each index. + # Schema: + # https://github.com/firefox-devtools/profiler/blob/main/docs-developer/gecko-profile-format.md + # https://github.com/firefox-devtools/profiler/blob/53970305b51b9b472e26d7457fee1d66cd4e2737/src/types/gecko-profile.js#L230 + return { + "tid": self.tid, + "pid": self.pid, + "name": self.comm, + # https://github.com/firefox-devtools/profiler/blob/53970305b51b9b472e26d7457fee1d66cd4e2737/src/types/gecko-profile.js#L51 + "markers": { + "schema": { + "name": 0, + "startTime": 1, + "endTime": 2, + "phase": 3, + "category": 4, + "data": 5, + }, + "data": [], + }, + + # https://github.com/firefox-devtools/profiler/blob/53970305b51b9b472e26d7457fee1d66cd4e2737/src/types/gecko-profile.js#L90 + "samples": { + "schema": { + "stack": 0, + "time": 1, + "responsiveness": 2, + }, + "data": self.samples + }, + + # https://github.com/firefox-devtools/profiler/blob/53970305b51b9b472e26d7457fee1d66cd4e2737/src/types/gecko-profile.js#L156 + "frameTable": { + "schema": { + "location": 0, + "relevantForJS": 1, + "innerWindowID": 2, + "implementation": 3, + "optimizations": 4, + "line": 5, + "column": 6, + "category": 7, + "subcategory": 8, + }, + "data": self.frameTable, + }, + + # https://github.com/firefox-devtools/profiler/blob/53970305b51b9b472e26d7457fee1d66cd4e2737/src/types/gecko-profile.js#L216 + "stackTable": { + "schema": { + "prefix": 0, + "frame": 1, + }, + "data": self.stackTable, + }, + "stringTable": self.stringTable, + "registerTime": 0, + "unregisterTime": None, + "processType": "default", + } + # Uses perf script python interface to parse each # event and store the data in the thread builder. def process_event(param_dict: Dict) -> None: -- GitLab From 833daec7e6cfda0d6c30a94c21b6706ff094cd45 Mon Sep 17 00:00:00 2001 From: Anup Sharma Date: Fri, 21 Jul 2023 23:24:42 +0530 Subject: [PATCH 0546/3445] perf scripts python: Add trace end processing and PRODUCT and CATEGORIES information The final output will now be presented in JSON format following the Gecko profile structure. Additionally, the inclusion of PRODUCT allows easy retrieval of header information for UI. Furthermore, CATEGORIES have been introduced to enable customization of kernel and user colors using input arguments. To facilitate this functionality, an argparse-based parser has been implemented. Note: The implementation of threads will be addressed in subsequent commits for now I have commented it out. Signed-off-by: Anup Sharma Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/fa6d027e4134c48e8a2ea45dd8f6b21e6a3418e4.1689961706.git.anupnewsmail@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/scripts/python/gecko.py | 65 +++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/tools/perf/scripts/python/gecko.py b/tools/perf/scripts/python/gecko.py index 2cd5cd6e31e35..794a91bec4640 100644 --- a/tools/perf/scripts/python/gecko.py +++ b/tools/perf/scripts/python/gecko.py @@ -11,6 +11,8 @@ import os import sys +import json +import argparse from dataclasses import dataclass, field from typing import List, Dict, Optional, NamedTuple, Set, Tuple, Any @@ -30,6 +32,13 @@ Milliseconds = float # start_time is intialiazed only once for the all event traces. start_time = None +# https://github.com/firefox-devtools/profiler/blob/53970305b51b9b472e26d7457fee1d66cd4e2737/src/types/profile.js#L425 +# Follow Brendan Gregg's Flamegraph convention: orange for kernel and yellow for user space by default. +CATEGORIES = None + +# The product name is used by the profiler UI to show the Operating system and Processor. +PRODUCT = os.popen('uname -op').read().strip() + # https://github.com/firefox-devtools/profiler/blob/53970305b51b9b472e26d7457fee1d66cd4e2737/src/types/gecko-profile.js#L156 class Frame(NamedTuple): string_id: StringID @@ -171,4 +180,58 @@ def process_event(param_dict: Dict) -> None: # Trace_end runs at the end and will be used to aggregate # the data into the final json object and print it out to stdout. def trace_end() -> None: - pass + # Schema: https://github.com/firefox-devtools/profiler/blob/53970305b51b9b472e26d7457fee1d66cd4e2737/src/types/gecko-profile.js#L305 + gecko_profile_with_meta = { + "meta": { + "interval": 1, + "processType": 0, + "product": PRODUCT, + "stackwalk": 1, + "debug": 0, + "gcpoison": 0, + "asyncstack": 1, + "startTime": start_time, + "shutdownTime": None, + "version": 24, + "presymbolicated": True, + "categories": CATEGORIES, + "markerSchema": [], + }, + "libs": [], + # threads will be implemented in later commits. + # "threads": threads, + "processes": [], + "pausedRanges": [], + } + json.dump(gecko_profile_with_meta, sys.stdout, indent=2) + +def main() -> None: + global CATEGORIES + parser = argparse.ArgumentParser(description="Convert perf.data to Firefox\'s Gecko Profile format") + + # Add the command-line options + # Colors must be defined according to this: + # https://github.com/firefox-devtools/profiler/blob/50124adbfa488adba6e2674a8f2618cf34b59cd2/res/css/categories.css + parser.add_argument('--user-color', default='yellow', help='Color for the User category') + parser.add_argument('--kernel-color', default='orange', help='Color for the Kernel category') + # Parse the command-line arguments + args = parser.parse_args() + # Access the values provided by the user + user_color = args.user_color + kernel_color = args.kernel_color + + CATEGORIES = [ + { + "name": 'User', + "color": user_color, + "subcategories": ['Other'] + }, + { + "name": 'Kernel', + "color": kernel_color, + "subcategories": ['Other'] + }, + ] + +if __name__ == '__main__': + main() -- GitLab From 258dfd41c1df2030772ceab378f7bd6f0f78b938 Mon Sep 17 00:00:00 2001 From: Anup Sharma Date: Fri, 21 Jul 2023 23:25:38 +0530 Subject: [PATCH 0547/3445] perf scripts python: Implement add sample function and thread processing The intern_stack function is responsible for retrieving or creating a stack_id based on the provided frame_id and prefix_id. It first generates a key using the frame_id and prefix_id values. If the stack corresponding to the key is found in the stackMap, it is returned. Otherwise, a new stack is created by appending the prefix_id and frame_id to the stackTable. The key and the index of the newly created stack are added to the stackMap for future reference. The _intern_frame function is responsible for retrieving or creating a frame_id based on the provided frame string. If the frame_id corresponding to the frameString is found in the frameMap, it is returned. Otherwise, a new frame is created by appending relevant information to the frameTable and adding the frameString to the string_id through _intern_string. The _intern_string function will gets a matching string, or saves the new string and returns a String ID. Signed-off-by: Anup Sharma Link: https://lore.kernel.org/r/4442f4b1ab4c7317cf940560a3a285fcdfbeeb08.1689961706.git.anupnewsmail@gmail.com Cc: Mark Rutland Cc: Ian Rogers Cc: Peter Zijlstra Cc: Adrian Hunter Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Namhyung Kim Cc: Alexander Shishkin Cc: Ingo Molnar Cc: linux-kernel@vger.kernel.org Cc: linux-perf-users@vger.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/scripts/python/gecko.py | 54 ++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/tools/perf/scripts/python/gecko.py b/tools/perf/scripts/python/gecko.py index 794a91bec4640..97949249a3c00 100644 --- a/tools/perf/scripts/python/gecko.py +++ b/tools/perf/scripts/python/gecko.py @@ -13,6 +13,7 @@ import os import sys import json import argparse +from functools import reduce from dataclasses import dataclass, field from typing import List, Dict, Optional, NamedTuple, Set, Tuple, Any @@ -39,6 +40,10 @@ CATEGORIES = None # The product name is used by the profiler UI to show the Operating system and Processor. PRODUCT = os.popen('uname -op').read().strip() +# The category index is used by the profiler UI to show the color of the flame graph. +USER_CATEGORY_INDEX = 0 +KERNEL_CATEGORY_INDEX = 1 + # https://github.com/firefox-devtools/profiler/blob/53970305b51b9b472e26d7457fee1d66cd4e2737/src/types/gecko-profile.js#L156 class Frame(NamedTuple): string_id: StringID @@ -99,6 +104,55 @@ class Thread: stackMap: Dict[Tuple[Optional[int], int], int] = field(default_factory=dict) frameMap: Dict[str, int] = field(default_factory=dict) + def _intern_stack(self, frame_id: int, prefix_id: Optional[int]) -> int: + """Gets a matching stack, or saves the new stack. Returns a Stack ID.""" + key = f"{frame_id}" if prefix_id is None else f"{frame_id},{prefix_id}" + # key = (prefix_id, frame_id) + stack_id = self.stackMap.get(key) + if stack_id is None: + # return stack_id + stack_id = len(self.stackTable) + self.stackTable.append(Stack(prefix_id=prefix_id, frame_id=frame_id)) + self.stackMap[key] = stack_id + return stack_id + + def _intern_string(self, string: str) -> int: + """Gets a matching string, or saves the new string. Returns a String ID.""" + string_id = self.stringMap.get(string) + if string_id is not None: + return string_id + string_id = len(self.stringTable) + self.stringTable.append(string) + self.stringMap[string] = string_id + return string_id + + def _intern_frame(self, frame_str: str) -> int: + """Gets a matching stack frame, or saves the new frame. Returns a Frame ID.""" + frame_id = self.frameMap.get(frame_str) + if frame_id is not None: + return frame_id + frame_id = len(self.frameTable) + self.frameMap[frame_str] = frame_id + string_id = self._intern_string(frame_str) + + symbol_name_to_category = KERNEL_CATEGORY_INDEX if frame_str.find('kallsyms') != -1 \ + or frame_str.find('/vmlinux') != -1 \ + or frame_str.endswith('.ko)') \ + else USER_CATEGORY_INDEX + + self.frameTable.append(Frame( + string_id=string_id, + relevantForJS=False, + innerWindowID=0, + implementation=None, + optimizations=None, + line=None, + column=None, + category=symbol_name_to_category, + subcategory=None, + )) + return frame_id + def _to_json_dict(self) -> Dict: """Converts current Thread to GeckoThread JSON format.""" # Gecko profile format is row-oriented data as List[List], -- GitLab From 2d889c6af1cc125380b03b6efdaed0a4b4611aed Mon Sep 17 00:00:00 2001 From: Anup Sharma Date: Fri, 21 Jul 2023 23:26:24 +0530 Subject: [PATCH 0548/3445] perf scripts python: Implement add sample function and thread processing The stack has been created for storing func and dso from the callchain. The sample has been added to a specific thread. It first checks if the thread exists in the Thread class. Then it call _add_sample function which is responsible for appending a new entry to the samples list. Also callchain parsing and storing part is implemented. Moreover removed the comment from thread. Signed-off-by: Anup Sharma Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/5a112be85ccdcdcd611e343f6a7a7482d01f6299.1689961706.git.anupnewsmail@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/scripts/python/gecko.py | 52 ++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/tools/perf/scripts/python/gecko.py b/tools/perf/scripts/python/gecko.py index 97949249a3c00..278c3aed282a9 100644 --- a/tools/perf/scripts/python/gecko.py +++ b/tools/perf/scripts/python/gecko.py @@ -40,6 +40,9 @@ CATEGORIES = None # The product name is used by the profiler UI to show the Operating system and Processor. PRODUCT = os.popen('uname -op').read().strip() +# Here key = tid, value = Thread +tid_to_thread = dict() + # The category index is used by the profiler UI to show the color of the flame graph. USER_CATEGORY_INDEX = 0 KERNEL_CATEGORY_INDEX = 1 @@ -153,6 +156,25 @@ class Thread: )) return frame_id + def _add_sample(self, comm: str, stack: List[str], time_ms: Milliseconds) -> None: + """Add a timestamped stack trace sample to the thread builder. + Args: + comm: command-line (name) of the thread at this sample + stack: sampled stack frames. Root first, leaf last. + time_ms: timestamp of sample in milliseconds. + """ + # Ihreads may not set their names right after they are created. + # Instead, they might do it later. In such situations, to use the latest name they have set. + if self.comm != comm: + self.comm = comm + + prefix_stack_id = reduce(lambda prefix_id, frame: self._intern_stack + (self._intern_frame(frame), prefix_id), stack, None) + if prefix_stack_id is not None: + self.samples.append(Sample(stack_id=prefix_stack_id, + time_ms=time_ms, + responsiveness=0)) + def _to_json_dict(self) -> Dict: """Converts current Thread to GeckoThread JSON format.""" # Gecko profile format is row-oriented data as List[List], @@ -231,9 +253,36 @@ def process_event(param_dict: Dict) -> None: if not start_time: start_time = time_stamp + # Parse and append the callchain of the current sample into a stack. + stack = [] + if param_dict['callchain']: + for call in param_dict['callchain']: + if 'sym' not in call: + continue + stack.append(f'{call["sym"]["name"]} (in {call["dso"]})') + if len(stack) != 0: + # Reverse the stack, as root come first and the leaf at the end. + stack = stack[::-1] + + # During perf record if -g is not used, the callchain is not available. + # In that case, the symbol and dso are available in the event parameters. + else: + func = param_dict['symbol'] if 'symbol' in param_dict else '[unknown]' + dso = param_dict['dso'] if 'dso' in param_dict else '[unknown]' + stack.append(f'{func} (in {dso})') + + # Add sample to the specific thread. + thread = tid_to_thread.get(tid) + if thread is None: + thread = Thread(comm=comm, pid=pid, tid=tid) + tid_to_thread[tid] = thread + thread._add_sample(comm=comm, stack=stack, time_ms=time_stamp) + # Trace_end runs at the end and will be used to aggregate # the data into the final json object and print it out to stdout. def trace_end() -> None: + threads = [thread._to_json_dict() for thread in tid_to_thread.values()] + # Schema: https://github.com/firefox-devtools/profiler/blob/53970305b51b9b472e26d7457fee1d66cd4e2737/src/types/gecko-profile.js#L305 gecko_profile_with_meta = { "meta": { @@ -252,8 +301,7 @@ def trace_end() -> None: "markerSchema": [], }, "libs": [], - # threads will be implemented in later commits. - # "threads": threads, + "threads": threads, "processes": [], "pausedRanges": [], } -- GitLab From f9f72b2ab77e986ac30de09a735a002b37d81503 Mon Sep 17 00:00:00 2001 From: Anup Sharma Date: Fri, 21 Jul 2023 23:27:46 +0530 Subject: [PATCH 0549/3445] perf scripts python: Add command execution for gecko script This will enable the execution of gecko.py script using record and report commands in 'perf script'. And this will be also reflected at "perf script -l" command. For Example: perf script record gecko perf script report gecko Committer notes: As discussed on the perf tools office hours, I made -F 99 the default for the record script and removed the double -- on the report script so that the existing 'perf script' protocol for the combined operation: # perf script gecko Works, i.e. the record script pipes its stdout into the stdin of the report script, basically: /bin/sh /usr/libexec/perf-core/scripts/python/bin/gecko-record -F 99 -g -a -q -o - | \ /bin/sh /usr/libexec/perf-core/scripts/python/bin/gecko-report -i - Testing it: The resulting JSON file needs to be uploaded to https://profiler.firefox.com, Anup already has code to start a local http server on the trace_begin handler of the gecko python script, start firefox and feed it the JSON. The example below only collects sample for the specified workload, so that we don't produce thousands of lines, to collect system wide samples, use instead: # perf script gecko -a sleep 0.5 # nohup perf script gecko sleep 0.5 { "meta": { "interval": 1, "processType": 0, "product": "x86_64 GNU/Linux", "stackwalk": 1, "debug": 0, "gcpoison": 0, "asyncstack": 1, "startTime": 274601692.636, "shutdownTime": null, "version": 24, "presymbolicated": true, "categories": [ { "name": "User", "color": "yellow", "subcategories": [ "Other" ] }, { "name": "Kernel", "color": "orange", "subcategories": [ "Other" ] } ], "markerSchema": [] }, "libs": [], "threads": [ { "tid": 3344498, "pid": 3344498, "name": "sleep", "markers": { "schema": { "name": 0, "startTime": 1, "endTime": 2, "phase": 3, "category": 4, "data": 5 }, "data": [] }, "samples": { "schema": { "stack": 0, "time": 1, "responsiveness": 2 }, "data": [ [ 21, 274601692.636, 0 ], [ 23, 274601692.641, 0 ], [ 29, 274601692.643, 0 ], [ 42, 274601692.648, 0 ] ] }, "frameTable": { "schema": { "location": 0, "relevantForJS": 1, "innerWindowID": 2, "implementation": 3, "optimizations": 4, "line": 5, "column": 6, "category": 7, "subcategory": 8 }, "data": [ [ 0, false, 0, null, null, null, null, 1, null ], [ 1, false, 0, null, null, null, null, 1, null ], [ 2, false, 0, null, null, null, null, 1, null ], [ 3, false, 0, null, null, null, null, 1, null ], [ 4, false, 0, null, null, null, null, 1, null ], [ 5, false, 0, null, null, null, null, 1, null ], [ 6, false, 0, null, null, null, null, 1, null ], [ 7, false, 0, null, null, null, null, 1, null ], [ 8, false, 0, null, null, null, null, 1, null ], [ 9, false, 0, null, null, null, null, 1, null ], [ 10, false, 0, null, null, null, null, 1, null ], [ 11, false, 0, null, null, null, null, 1, null ], [ 12, false, 0, null, null, null, null, 1, null ], [ 13, false, 0, null, null, null, null, 1, null ], [ 14, false, 0, null, null, null, null, 1, null ], [ 15, false, 0, null, null, null, null, 1, null ], [ 16, false, 0, null, null, null, null, 1, null ], [ 17, false, 0, null, null, null, null, 1, null ], [ 18, false, 0, null, null, null, null, 1, null ], [ 19, false, 0, null, null, null, null, 1, null ], [ 20, false, 0, null, null, null, null, 1, null ], [ 21, false, 0, null, null, null, null, 1, null ], [ 22, false, 0, null, null, null, null, 1, null ], [ 23, false, 0, null, null, null, null, 1, null ], [ 24, false, 0, null, null, null, null, 1, null ], [ 25, false, 0, null, null, null, null, 1, null ], [ 26, false, 0, null, null, null, null, 1, null ], [ 27, false, 0, null, null, null, null, 1, null ], [ 28, false, 0, null, null, null, null, 1, null ], [ 29, false, 0, null, null, null, null, 1, null ], [ 30, false, 0, null, null, null, null, 1, null ], [ 31, false, 0, null, null, null, null, 1, null ], [ 32, false, 0, null, null, null, null, 1, null ], [ 33, false, 0, null, null, null, null, 1, null ], [ 34, false, 0, null, null, null, null, 1, null ], [ 35, false, 0, null, null, null, null, 1, null ], [ 36, false, 0, null, null, null, null, 1, null ], [ 37, false, 0, null, null, null, null, 1, null ], [ 38, false, 0, null, null, null, null, 1, null ] ] }, "stackTable": { "schema": { "prefix": 0, "frame": 1 }, "data": [ [ null, 0 ], [ 0, 1 ], [ 1, 2 ], [ 2, 3 ], [ 3, 4 ], [ 4, 5 ], [ 5, 6 ], [ 6, 7 ], [ 7, 8 ], [ 8, 9 ], [ 9, 10 ], [ 10, 11 ], [ 11, 12 ], [ 12, 13 ], [ 13, 14 ], [ 14, 15 ], [ 15, 16 ], [ 16, 17 ], [ 17, 18 ], [ 18, 19 ], [ 19, 20 ], [ 20, 21 ], [ 20, 22 ], [ 22, 23 ], [ 11, 24 ], [ 24, 25 ], [ 25, 26 ], [ 26, 27 ], [ 27, 28 ], [ 28, 29 ], [ 9, 11 ], [ 30, 24 ], [ 31, 25 ], [ 32, 30 ], [ 33, 31 ], [ 34, 32 ], [ 35, 29 ], [ 36, 33 ], [ 37, 34 ], [ 38, 35 ], [ 39, 36 ], [ 40, 37 ], [ 41, 38 ] ] }, "stringTable": [ "__func__.0 (in [kernel.kallsyms].rodata)", "perf_trace_ext4_fc_track_inode (in [kernel.kallsyms])", "perf_trace_ext4_es_insert_delayed_block (in [kernel.kallsyms])", "ext4_es_show_pblock (in [kernel.kallsyms])", "perf_trace_ext4_ext_rm_leaf (in [kernel.kallsyms])", "devcgroup_access_write (in [kernel.kallsyms])", "devcgroup_update_access (in [kernel.kallsyms])", "propagate_exception (in [kernel.kallsyms])", "revalidate_active_exceptions (in [kernel.kallsyms])", "perf_trace_ext4_fc_commit_stop (in [kernel.kallsyms])", "perf_fetch_caller_regs (in [kernel.kallsyms])", "khugepaged (in [kernel.kallsyms])", "khugepaged_wait_work (in [kernel.kallsyms])", "freezable_schedule_timeout (in [kernel.kallsyms])", "freezer_count (in [kernel.kallsyms])", "try_to_freeze (in [kernel.kallsyms])", "try_to_freeze_unsafe (in [kernel.kallsyms])", "split_huge_pages_write (in [kernel.kallsyms])", "migrate_pages (in [kernel.kallsyms])", "unmap_and_move (in [kernel.kallsyms])", "__unmap_and_move (in [kernel.kallsyms])", "collect_events (in [kernel.kallsyms])", "uncore_down_prepare (in [kernel.kallsyms])", "perf_iommu_read (in [kernel.kallsyms])", "khugepaged_do_scan (in [kernel.kallsyms])", "khugepaged_scan_mm_slot (in [kernel.kallsyms])", "khugepaged_scan_file (in [kernel.kallsyms])", "need_resched (in [kernel.kallsyms])", "get_current (in [kernel.kallsyms])", "move_to_new_page (in [kernel.kallsyms])", "khugepaged_scan_pmd (in [kernel.kallsyms])", "trace_mm_khugepaged_scan_pmd (in [kernel.kallsyms])", "migrate_huge_page_move_mapping (in [kernel.kallsyms])", "do_huge_pmd_numa_page (in [kernel.kallsyms])", "pmd_pfn (in [kernel.kallsyms])", "protnone_mask (in [kernel.kallsyms])", "__pte_needs_invert (in [kernel.kallsyms])", "reclaim_high (in [kernel.kallsyms])", "memcg_memory_event (in [kernel.kallsyms])" ], "registerTime": 0, "unregisterTime": null, "processType": "default" } ], "processes": [], "pausedRanges": [] } # Signed-off-by: Anup Sharma Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/cbf03cda175ea3dd2c6cd87bd3f12d803446cb95.1689961706.git.anupnewsmail@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/scripts/python/bin/gecko-record | 2 ++ tools/perf/scripts/python/bin/gecko-report | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 tools/perf/scripts/python/bin/gecko-record create mode 100644 tools/perf/scripts/python/bin/gecko-report diff --git a/tools/perf/scripts/python/bin/gecko-record b/tools/perf/scripts/python/bin/gecko-record new file mode 100644 index 0000000000000..f0d1aa55f171e --- /dev/null +++ b/tools/perf/scripts/python/bin/gecko-record @@ -0,0 +1,2 @@ +#!/bin/bash +perf record -F 99 -g "$@" diff --git a/tools/perf/scripts/python/bin/gecko-report b/tools/perf/scripts/python/bin/gecko-report new file mode 100644 index 0000000000000..0c12cc08f3ab3 --- /dev/null +++ b/tools/perf/scripts/python/bin/gecko-report @@ -0,0 +1,3 @@ +#!/bin/bash +# description: create firefox gecko profile json format from perf.data +perf script "$@" -s "$PERF_EXEC_PATH"/scripts/python/gecko.py -- GitLab From 404e077a16bb7796908b604b2df02cd650c965aa Mon Sep 17 00:00:00 2001 From: James Clark Date: Wed, 28 Jun 2023 11:53:02 +0100 Subject: [PATCH 0550/3445] perf tools: Add a place to put kernel config fragments for test runs Defconfig doesn't give full coverage for a perf test run, so these can be merged with defconfig to do so. It's not complete yet, but is a starting point as a place to add to when a specific test needs something extra to run. Signed-off-by: James Clark Cc: Adrian Hunter Cc: Aishwarya.TCV@arm.com Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Leo Yan Cc: Mark Brown Cc: Mark Rutland Cc: Masahiro Yamada Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20230628105303.4053478-2-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/config-fragments/README | 7 +++++++ tools/perf/tests/config-fragments/arm64 | 1 + tools/perf/tests/config-fragments/config | 11 +++++++++++ 3 files changed, 19 insertions(+) create mode 100644 tools/perf/tests/config-fragments/README create mode 100644 tools/perf/tests/config-fragments/arm64 create mode 100644 tools/perf/tests/config-fragments/config diff --git a/tools/perf/tests/config-fragments/README b/tools/perf/tests/config-fragments/README new file mode 100644 index 0000000000000..fe7de5d936749 --- /dev/null +++ b/tools/perf/tests/config-fragments/README @@ -0,0 +1,7 @@ +This folder is for kernel config fragments that can be merged with +defconfig to give full test coverage of a perf test run. This is only +an optimistic set as some features require hardware support in order to +pass and not skip. + +'config' is shared across all platforms, and for arch specific files, +the file name should match that used in the ARCH=... make option. diff --git a/tools/perf/tests/config-fragments/arm64 b/tools/perf/tests/config-fragments/arm64 new file mode 100644 index 0000000000000..64c4ab17cd58d --- /dev/null +++ b/tools/perf/tests/config-fragments/arm64 @@ -0,0 +1 @@ +CONFIG_CORESIGHT_SOURCE_ETM4X=y diff --git a/tools/perf/tests/config-fragments/config b/tools/perf/tests/config-fragments/config new file mode 100644 index 0000000000000..c340b3195fcaa --- /dev/null +++ b/tools/perf/tests/config-fragments/config @@ -0,0 +1,11 @@ +CONFIG_TRACEPOINTS=y +CONFIG_STACKTRACE=y +CONFIG_NOP_TRACER=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_FTRACE=y +CONFIG_FTRACE_SYSCALLS=y +CONFIG_BRANCH_PROFILE_NONE=y -- GitLab From 24069d8112c94e76758da83a5bddc9aa98601d22 Mon Sep 17 00:00:00 2001 From: Jing Zhang Date: Fri, 28 Jul 2023 15:09:33 +0800 Subject: [PATCH 0551/3445] perf jevents: Add support for Yitian 710 DDR PMU (arm64) aliasing Add alias support for T-HEAD Yitian 710 SoC DDR PMU events. Reviewed-by: John Garry Reviewed-by: Shuai Xue Signed-off-by: Jing Zhang Acked-by: Ian Rogers Cc: Namhyung Kim Cc: Will Deacon Cc: Zhuo Song Cc: linux-arm-kernel@lists.infradead.org Cc: linux-doc@vger.kernel.org Link: https://lore.kernel.org/r/1690528175-2499-2-git-send-email-renyu.zj@linux.alibaba.com Signed-off-by: Arnaldo Carvalho de Melo --- .../freescale/yitian710/sys/ali_drw.json | 373 ++++++++++++++++++ tools/perf/pmu-events/jevents.py | 1 + 2 files changed, 374 insertions(+) create mode 100644 tools/perf/pmu-events/arch/arm64/freescale/yitian710/sys/ali_drw.json diff --git a/tools/perf/pmu-events/arch/arm64/freescale/yitian710/sys/ali_drw.json b/tools/perf/pmu-events/arch/arm64/freescale/yitian710/sys/ali_drw.json new file mode 100644 index 0000000000000..e21c469a8ef0f --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/freescale/yitian710/sys/ali_drw.json @@ -0,0 +1,373 @@ +[ + { + "BriefDescription": "A Write or Read Op at HIF interface. The unit is 64B.", + "ConfigCode": "0x0", + "EventName": "hif_rd_or_wr", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A Write Op at HIF interface. The unit is 64B.", + "ConfigCode": "0x1", + "EventName": "hif_wr", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A Read Op at HIF interface. The unit is 64B.", + "ConfigCode": "0x2", + "EventName": "hif_rd", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A Read-Modify-Write Op at HIF interface. The unit is 64B.", + "ConfigCode": "0x3", + "EventName": "hif_rmw", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A high priority Read at HIF interface. The unit is 64B.", + "ConfigCode": "0x4", + "EventName": "hif_hi_pri_rd", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A write data cycle at DFI interface (to DRAM).", + "ConfigCode": "0x7", + "EventName": "dfi_wr_data_cycles", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A read data cycle at DFI interface (to DRAM).", + "ConfigCode": "0x8", + "EventName": "dfi_rd_data_cycles", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A high priority read becomes critical.", + "ConfigCode": "0x9", + "EventName": "hpr_xact_when_critical", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A low priority read becomes critical.", + "ConfigCode": "0xA", + "EventName": "lpr_xact_when_critical", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A write becomes critical.", + "ConfigCode": "0xB", + "EventName": "wr_xact_when_critical", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "An Activate(ACT) command to DRAM.", + "ConfigCode": "0xC", + "EventName": "op_is_activate", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A Read or Write CAS command to DRAM.", + "ConfigCode": "0xD", + "EventName": "op_is_rd_or_wr", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "An Activate(ACT) command for read to DRAM.", + "ConfigCode": "0xE", + "EventName": "op_is_rd_activate", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A Read CAS command to DRAM.", + "ConfigCode": "0xF", + "EventName": "op_is_rd", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A Write CAS command to DRAM.", + "ConfigCode": "0x10", + "EventName": "op_is_wr", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A Masked Write command to DRAM.", + "ConfigCode": "0x11", + "EventName": "op_is_mwr", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A Precharge(PRE) command to DRAM.", + "ConfigCode": "0x12", + "EventName": "op_is_precharge", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A Precharge(PRE) required by read or write.", + "ConfigCode": "0x13", + "EventName": "precharge_for_rdwr", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A Precharge(PRE) required by other conditions.", + "ConfigCode": "0x14", + "EventName": "precharge_for_other", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A read-write turnaround.", + "ConfigCode": "0x15", + "EventName": "rdwr_transitions", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A write combine(merge) in write data buffer.", + "ConfigCode": "0x16", + "EventName": "write_combine", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A Write-After-Read hazard.", + "ConfigCode": "0x17", + "EventName": "war_hazard", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A Read-After-Write hazard.", + "ConfigCode": "0x18", + "EventName": "raw_hazard", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A Write-After-Write hazard.", + "ConfigCode": "0x19", + "EventName": "waw_hazard", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "Rank0 enters self-refresh(SRE).", + "ConfigCode": "0x1A", + "EventName": "op_is_enter_selfref_rk0", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "Rank1 enters self-refresh(SRE).", + "ConfigCode": "0x1B", + "EventName": "op_is_enter_selfref_rk1", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "Rank2 enters self-refresh(SRE).", + "ConfigCode": "0x1C", + "EventName": "op_is_enter_selfref_rk2", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "Rank3 enters self-refresh(SRE).", + "ConfigCode": "0x1D", + "EventName": "op_is_enter_selfref_rk3", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "Rank0 enters power-down(PDE).", + "ConfigCode": "0x1E", + "EventName": "op_is_enter_powerdown_rk0", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "Rank1 enters power-down(PDE).", + "ConfigCode": "0x1F", + "EventName": "op_is_enter_powerdown_rk1", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "Rank2 enters power-down(PDE).", + "ConfigCode": "0x20", + "EventName": "op_is_enter_powerdown_rk2", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "Rank3 enters power-down(PDE).", + "ConfigCode": "0x21", + "EventName": "op_is_enter_powerdown_rk3", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A cycle that Rank0 stays in self-refresh mode.", + "ConfigCode": "0x26", + "EventName": "selfref_mode_rk0", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A cycle that Rank1 stays in self-refresh mode.", + "ConfigCode": "0x27", + "EventName": "selfref_mode_rk1", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A cycle that Rank2 stays in self-refresh mode.", + "ConfigCode": "0x28", + "EventName": "selfref_mode_rk2", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A cycle that Rank3 stays in self-refresh mode.", + "ConfigCode": "0x29", + "EventName": "selfref_mode_rk3", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "An auto-refresh(REF) command to DRAM.", + "ConfigCode": "0x2A", + "EventName": "op_is_refresh", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A critical auto-refresh(REF) command to DRAM.", + "ConfigCode": "0x2B", + "EventName": "op_is_crit_ref", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "An MRR or MRW command to DRAM.", + "ConfigCode": "0x2D", + "EventName": "op_is_load_mode", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A ZQCal command to DRAM.", + "ConfigCode": "0x2E", + "EventName": "op_is_zqcl", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "At least one entry in read queue reaches the visible window limit.", + "ConfigCode": "0x30", + "EventName": "visible_window_limit_reached_rd", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "At least one entry in write queue reaches the visible window limit.", + "ConfigCode": "0x31", + "EventName": "visible_window_limit_reached_wr", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A DQS Oscillator MPC command to DRAM.", + "ConfigCode": "0x34", + "EventName": "op_is_dqsosc_mpc", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A DQS Oscillator MRR command to DRAM.", + "ConfigCode": "0x35", + "EventName": "op_is_dqsosc_mrr", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A Temperature Compensated Refresh(TCR) MRR command to DRAM.", + "ConfigCode": "0x36", + "EventName": "op_is_tcr_mrr", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A ZQCal Start command to DRAM.", + "ConfigCode": "0x37", + "EventName": "op_is_zqstart", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A ZQCal Latch command to DRAM.", + "ConfigCode": "0x38", + "EventName": "op_is_zqlatch", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A packet at CHI TXREQ interface (request).", + "ConfigCode": "0x39", + "EventName": "chi_txreq", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A packet at CHI TXDAT interface (read data).", + "ConfigCode": "0x3A", + "EventName": "chi_txdat", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A packet at CHI RXDAT interface (write data).", + "ConfigCode": "0x3B", + "EventName": "chi_rxdat", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A packet at CHI RXRSP interface.", + "ConfigCode": "0x3C", + "EventName": "chi_rxrsp", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "A violation detected in TZC.", + "ConfigCode": "0x3D", + "EventName": "tsz_vio", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "BriefDescription": "The ddr cycles.", + "ConfigCode": "0x80", + "EventName": "ddr_cycles", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + } +] diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py index 12e80bb7939be..08ec9aa583e73 100755 --- a/tools/perf/pmu-events/jevents.py +++ b/tools/perf/pmu-events/jevents.py @@ -274,6 +274,7 @@ class JsonEvent: 'DFPMC': 'amd_df', 'cpu_core': 'cpu_core', 'cpu_atom': 'cpu_atom', + 'ali_drw': 'ali_drw', } return table[unit] if unit in table else f'uncore_{unit.lower()}' -- GitLab From 3e65bd13746af54bbe9a9c415a437bcc0b78282c Mon Sep 17 00:00:00 2001 From: Jing Zhang Date: Fri, 28 Jul 2023 15:09:34 +0800 Subject: [PATCH 0552/3445] perf vendor events arm64: Add JSON metrics for Yitian 710 DDR Add JSON metrics for T-HEAD Yitian 710 SoC DDR. Reviewed-by: John Garry Signed-off-by: Jing Zhang Acked-by: Ian Rogers Cc: Namhyung Kim Cc: Shuai Xue Cc: Will Deacon Cc: Zhuo Song Cc: linux-arm-kernel@lists.infradead.org Cc: linux-doc@vger.kernel.org Link: https://lore.kernel.org/r/1690528175-2499-3-git-send-email-renyu.zj@linux.alibaba.com Signed-off-by: Arnaldo Carvalho de Melo --- .../freescale/yitian710/sys/metrics.json | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tools/perf/pmu-events/arch/arm64/freescale/yitian710/sys/metrics.json diff --git a/tools/perf/pmu-events/arch/arm64/freescale/yitian710/sys/metrics.json b/tools/perf/pmu-events/arch/arm64/freescale/yitian710/sys/metrics.json new file mode 100644 index 0000000000000..bc865b374b6a8 --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/freescale/yitian710/sys/metrics.json @@ -0,0 +1,20 @@ +[ + { + "MetricName": "ddr_read_bandwidth.all", + "BriefDescription": "The ddr read bandwidth(MB/s).", + "MetricGroup": "ali_drw", + "MetricExpr": "hif_rd * 64 / 1e6 / duration_time", + "ScaleUnit": "1MB/s", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + }, + { + "MetricName": "ddr_write_bandwidth.all", + "BriefDescription": "The ddr write bandwidth(MB/s).", + "MetricGroup": "ali_drw", + "MetricExpr": "(hif_wr + hif_rmw) * 64 / 1e6 / duration_time", + "ScaleUnit": "1MB/s", + "Unit": "ali_drw", + "Compat": "ali_drw_pmu" + } +] -- GitLab From f849ce6baf467ea7fb9e68ae05d5d045f3aa89e8 Mon Sep 17 00:00:00 2001 From: Jing Zhang Date: Fri, 28 Jul 2023 15:09:35 +0800 Subject: [PATCH 0553/3445] perf docs: Update metric usage for Alibaba's T-Head PMU driver (arm64) Alibaba's T-Head ali_drw PMU supports DDR bandwidth metrics. Update its usage in the documentation. Reviewed-by: John Garry Signed-off-by: Jing Zhang Acked-by: Ian Rogers Cc: Namhyung Kim Cc: Shuai Xue Cc: Will Deacon Cc: Zhuo Song Cc: linux-arm-kernel@lists.infradead.org Cc: linux-doc@vger.kernel.org Link: https://lore.kernel.org/r/1690528175-2499-4-git-send-email-renyu.zj@linux.alibaba.com Signed-off-by: Arnaldo Carvalho de Melo --- Documentation/admin-guide/perf/alibaba_pmu.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/admin-guide/perf/alibaba_pmu.rst b/Documentation/admin-guide/perf/alibaba_pmu.rst index 11de998bb4806..7d840023903f5 100644 --- a/Documentation/admin-guide/perf/alibaba_pmu.rst +++ b/Documentation/admin-guide/perf/alibaba_pmu.rst @@ -88,6 +88,11 @@ data bandwidth:: -e ali_drw_27080/hif_rmw/ \ -e ali_drw_27080/cycle/ -- sleep 10 +Example usage of counting all memory read/write bandwidth by metric:: + + perf stat -M ddr_read_bandwidth.all -- sleep 10 + perf stat -M ddr_write_bandwidth.all -- sleep 10 + The average DRAM bandwidth can be calculated as follows: - Read Bandwidth = perf_hif_rd * DDRC_WIDTH * DDRC_Freq / DDRC_Cycle -- GitLab From 1134f290d07c251969d731781863dc513d81d049 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 27 Jul 2023 23:49:12 -0700 Subject: [PATCH 0554/3445] perf bpf-loader: Remove unneeded diagnostic pragma Added during the progress to libbpf 1.0 the deprecated functions are no longer used and so the pragma can be removed. Signed-off-by: Ian Rogers Acked-by: James Clark Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andrii Nakryiko Cc: Eduard Zingerman Cc: Gaosheng Cui Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Nick Desaulniers Cc: Peter Zijlstra Cc: Rob Herring Cc: Tom Rix Cc: bpf@vger.kernel.org Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230728064917.767761-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/bpf-loader.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 44cde27d63894..8f4c76f2265a4 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -32,9 +32,6 @@ #include -/* temporarily disable libbpf deprecation warnings */ -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - static int libbpf_perf_print(enum libbpf_print_level level __attribute__((unused)), const char *fmt, va_list args) { -- GitLab From 435bea0a45cb309772b22c56b2d570f743f655e0 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 27 Jul 2023 23:49:13 -0700 Subject: [PATCH 0555/3445] perf build: Don't always set -funwind-tables and -ggdb3 Commit 6a40cd90f5deb6de ("perf tools: Add libunwind dependency for DWARF CFI unwinding") added libunwind support but also -funwind-tables and -ggdb3 to the standard build. These build flags aren't necessary so remove, set -g when DEBUG is enabled for the build. Signed-off-by: Ian Rogers Acked-by: James Clark Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andrii Nakryiko Cc: Eduard Zingerman Cc: Gaosheng Cui Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Nick Desaulniers Cc: Peter Zijlstra Cc: Rob Herring Cc: Tom Rix Cc: bpf@vger.kernel.org Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230728064917.767761-3-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.config | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index a9cfe83638a93..14709a6bd622e 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -246,6 +246,9 @@ ifeq ($(CC_NO_CLANG), 0) else CORE_CFLAGS += -O6 endif +else + CORE_CFLAGS += -g + CXXFLAGS += -g endif ifdef PARSER_DEBUG @@ -324,8 +327,6 @@ FEATURE_CHECK_LDFLAGS-disassembler-four-args = -lbfd -lopcodes -ldl FEATURE_CHECK_LDFLAGS-disassembler-init-styled = -lbfd -lopcodes -ldl CORE_CFLAGS += -fno-omit-frame-pointer -CORE_CFLAGS += -ggdb3 -CORE_CFLAGS += -funwind-tables CORE_CFLAGS += -Wall CORE_CFLAGS += -Wextra CORE_CFLAGS += -std=gnu11 @@ -333,8 +334,6 @@ CORE_CFLAGS += -std=gnu11 CXXFLAGS += -std=gnu++14 -fno-exceptions -fno-rtti CXXFLAGS += -Wall CXXFLAGS += -fno-omit-frame-pointer -CXXFLAGS += -ggdb3 -CXXFLAGS += -funwind-tables CXXFLAGS += -Wno-strict-aliasing HOSTCFLAGS += -Wall -- GitLab From e5764ae4c9714e58fa3c38a7e4900d4379dc2263 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 27 Jul 2023 23:49:14 -0700 Subject: [PATCH 0556/3445] perf build: Add Wextra for C++ compilation Commit d58ac0bf8d1e ("perf build: Add clang and llvm compile and linking support") added -Wall and -Wno-strict-aliasing for CXXFLAGS, but not -Wextra. -Wno-strict-aliasing is no longer necessary, adding -Wextra for CXXFLAGS requires adding -Wno-unused-parameter clang.cpp and clang-test.cpp for LIBCLANGLLVM=1 to build. Signed-off-by: Ian Rogers Acked-by: James Clark Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andrii Nakryiko Cc: Eduard Zingerman Cc: Gaosheng Cui Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Nick Desaulniers Cc: Peter Zijlstra Cc: Rob Herring Cc: Tom Rix Cc: bpf@vger.kernel.org Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230728064917.767761-4-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.config | 2 +- tools/perf/util/c++/Build | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 14709a6bd622e..fe7afe6d8529f 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -333,8 +333,8 @@ CORE_CFLAGS += -std=gnu11 CXXFLAGS += -std=gnu++14 -fno-exceptions -fno-rtti CXXFLAGS += -Wall +CXXFLAGS += -Wextra CXXFLAGS += -fno-omit-frame-pointer -CXXFLAGS += -Wno-strict-aliasing HOSTCFLAGS += -Wall HOSTCFLAGS += -Wextra diff --git a/tools/perf/util/c++/Build b/tools/perf/util/c++/Build index 613ecfd76527d..8610d032ac19d 100644 --- a/tools/perf/util/c++/Build +++ b/tools/perf/util/c++/Build @@ -1,2 +1,5 @@ perf-$(CONFIG_CLANGLLVM) += clang.o perf-$(CONFIG_CLANGLLVM) += clang-test.o + +CXXFLAGS_clang.o += -Wno-unused-parameter +CXXFLAGS_clang-test.o += -Wno-unused-parameter -- GitLab From b265ee7bae1192ecc55ecaf7e63c8ed84cc2f509 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Thu, 15 Jun 2023 16:37:49 +1000 Subject: [PATCH 0557/3445] KVM: SEV: move set_dr_intercepts/clr_dr_intercepts from the header Static functions set_dr_intercepts() and clr_dr_intercepts() are only called from SVM so move them to .c. No functional change intended. Signed-off-by: Alexey Kardashevskiy Reviewed-by: Carlos Bilbao Reviewed-by: Tom Lendacky Reviewed-by: Santosh Shukla Link: https://lore.kernel.org/r/20230615063757.3039121-2-aik@amd.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/svm.c | 42 ++++++++++++++++++++++++++++++++++++++++++ arch/x86/kvm/svm/svm.h | 42 ------------------------------------------ 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index d381ad4245542..42f17ae99c9ee 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -677,6 +677,48 @@ free_save_area: } +static void set_dr_intercepts(struct vcpu_svm *svm) +{ + struct vmcb *vmcb = svm->vmcb01.ptr; + + if (!sev_es_guest(svm->vcpu.kvm)) { + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR0_READ); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR1_READ); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR2_READ); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR3_READ); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR4_READ); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR5_READ); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR6_READ); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR0_WRITE); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR1_WRITE); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR2_WRITE); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR3_WRITE); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR4_WRITE); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR5_WRITE); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR6_WRITE); + } + + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_READ); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_WRITE); + + recalc_intercepts(svm); +} + +static void clr_dr_intercepts(struct vcpu_svm *svm) +{ + struct vmcb *vmcb = svm->vmcb01.ptr; + + vmcb->control.intercepts[INTERCEPT_DR] = 0; + + /* DR7 access must remain intercepted for an SEV-ES guest */ + if (sev_es_guest(svm->vcpu.kvm)) { + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_READ); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_WRITE); + } + + recalc_intercepts(svm); +} + static int direct_access_msr_slot(u32 msr) { u32 i; diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 18af7e712a5ae..800ca1776b59b 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -404,48 +404,6 @@ static inline bool vmcb12_is_intercept(struct vmcb_ctrl_area_cached *control, u3 return test_bit(bit, (unsigned long *)&control->intercepts); } -static inline void set_dr_intercepts(struct vcpu_svm *svm) -{ - struct vmcb *vmcb = svm->vmcb01.ptr; - - if (!sev_es_guest(svm->vcpu.kvm)) { - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR0_READ); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR1_READ); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR2_READ); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR3_READ); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR4_READ); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR5_READ); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR6_READ); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR0_WRITE); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR1_WRITE); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR2_WRITE); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR3_WRITE); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR4_WRITE); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR5_WRITE); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR6_WRITE); - } - - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_READ); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_WRITE); - - recalc_intercepts(svm); -} - -static inline void clr_dr_intercepts(struct vcpu_svm *svm) -{ - struct vmcb *vmcb = svm->vmcb01.ptr; - - vmcb->control.intercepts[INTERCEPT_DR] = 0; - - /* DR7 access must remain intercepted for an SEV-ES guest */ - if (sev_es_guest(svm->vcpu.kvm)) { - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_READ); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_WRITE); - } - - recalc_intercepts(svm); -} - static inline void set_exception_intercept(struct vcpu_svm *svm, u32 bit) { struct vmcb *vmcb = svm->vmcb01.ptr; -- GitLab From 29de732cc95cb5219d8c2bd145cb7293cb572fc3 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Thu, 15 Jun 2023 16:37:50 +1000 Subject: [PATCH 0558/3445] KVM: SEV: Move SEV's GP_VECTOR intercept setup to SEV Currently SVM setup is done sequentially in init_vmcb() -> sev_init_vmcb() -> sev_es_init_vmcb() and tries keeping SVM/SEV/SEV-ES bits separated. One of the exceptions is #GP intercept which init_vmcb() skips setting for SEV guests and then sev_es_init_vmcb() needlessly clears it. Remove the SEV check from init_vmcb(). Clear the #GP intercept in sev_init_vmcb(). SEV-ES will use the SEV setting. No functional change intended. Suggested-by: Sean Christopherson Signed-off-by: Alexey Kardashevskiy Reviewed-by: Carlos Bilbao Reviewed-by: Tom Lendacky Reviewed-by: Santosh Shukla Link: https://lore.kernel.org/r/20230615063757.3039121-3-aik@amd.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 9 ++++++--- arch/x86/kvm/svm/svm.c | 5 ++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 07756b7348ae8..fd6e316c1a23d 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -2974,9 +2974,6 @@ static void sev_es_init_vmcb(struct vcpu_svm *svm) svm_set_intercept(svm, TRAP_CR4_WRITE); svm_set_intercept(svm, TRAP_CR8_WRITE); - /* No support for enable_vmware_backdoor */ - clr_exception_intercept(svm, GP_VECTOR); - /* Can't intercept XSETBV, HV can't modify XCR0 directly */ svm_clr_intercept(svm, INTERCEPT_XSETBV); @@ -3002,6 +2999,12 @@ void sev_init_vmcb(struct vcpu_svm *svm) svm->vmcb->control.nested_ctl |= SVM_NESTED_CTL_SEV_ENABLE; clr_exception_intercept(svm, UD_VECTOR); + /* + * Don't intercept #GP for SEV guests, e.g. for the VMware backdoor, as + * KVM can't decrypt guest memory to decode the faulting instruction. + */ + clr_exception_intercept(svm, GP_VECTOR); + if (sev_es_guest(svm->vcpu.kvm)) sev_es_init_vmcb(svm); } diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 42f17ae99c9ee..a0e803f2a574e 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -1243,10 +1243,9 @@ static void init_vmcb(struct kvm_vcpu *vcpu) * Guest access to VMware backdoor ports could legitimately * trigger #GP because of TSS I/O permission bitmap. * We intercept those #GP and allow access to them anyway - * as VMware does. Don't intercept #GP for SEV guests as KVM can't - * decrypt guest memory to decode the faulting instruction. + * as VMware does. */ - if (enable_vmware_backdoor && !sev_guest(vcpu->kvm)) + if (enable_vmware_backdoor) set_exception_intercept(svm, GP_VECTOR); svm_set_intercept(svm, INTERCEPT_INTR); -- GitLab From f8d808ed1ba0019997f18ff2be0cf85e33a31022 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 15 Jun 2023 16:37:51 +1000 Subject: [PATCH 0559/3445] KVM: SVM: Rewrite sev_es_prepare_switch_to_guest()'s comment about swap types Rewrite the comment(s) in sev_es_prepare_switch_to_guest() to explain the swap types employed by the CPU for SEV-ES guests, i.e. to explain why KVM needs to save a seemingly random subset of host state, and to provide a decoder for the APM's Type-A/B/C terminology. Signed-off-by: Alexey Kardashevskiy Link: https://lore.kernel.org/r/20230615063757.3039121-4-aik@amd.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index fd6e316c1a23d..d58a25a92aa3f 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -3023,19 +3023,24 @@ void sev_es_vcpu_reset(struct vcpu_svm *svm) void sev_es_prepare_switch_to_guest(struct sev_es_save_area *hostsa) { /* - * As an SEV-ES guest, hardware will restore the host state on VMEXIT, - * of which one step is to perform a VMLOAD. KVM performs the - * corresponding VMSAVE in svm_prepare_guest_switch for both - * traditional and SEV-ES guests. + * All host state for SEV-ES guests is categorized into three swap types + * based on how it is handled by hardware during a world switch: + * + * A: VMRUN: Host state saved in host save area + * VMEXIT: Host state loaded from host save area + * + * B: VMRUN: Host state _NOT_ saved in host save area + * VMEXIT: Host state loaded from host save area + * + * C: VMRUN: Host state _NOT_ saved in host save area + * VMEXIT: Host state initialized to default(reset) values + * + * Manually save type-B state, i.e. state that is loaded by VMEXIT but + * isn't saved by VMRUN, that isn't already saved by VMSAVE (performed + * by common SVM code). */ - - /* XCR0 is restored on VMEXIT, save the current host value */ hostsa->xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK); - - /* PKRU is restored on VMEXIT, save the current host value */ hostsa->pkru = read_pkru(); - - /* MSR_IA32_XSS is restored on VMEXIT, save the currnet host value */ hostsa->xss = host_xss; } -- GitLab From 2837dd00f8fc69111cd6b1dc8481d2fb490d11c9 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Thu, 15 Jun 2023 16:37:52 +1000 Subject: [PATCH 0560/3445] KVM: SEV-ES: explicitly disable debug SVM/SEV enable debug registers intercepts to skip swapping DRs on entering/exiting the guest. When the guest is in control of debug registers (vcpu->guest_debug == 0), there is an optimisation to reduce the number of context switches: intercepts are cleared and the KVM_DEBUGREG_WONT_EXIT flag is set to tell KVM to do swapping on guest enter/exit. The same code also executes for SEV-ES, however it has no effect as - it always takes (vcpu->guest_debug == 0) branch; - KVM_DEBUGREG_WONT_EXIT is set but DR7 intercept is not cleared; - vcpu_enter_guest() writes DRs but VMRUN for SEV-ES swaps them with the values from _encrypted_ VMSA. Be explicit about SEV-ES not supporting debug: - return right away from dr_interception() and skip unnecessary processing; - return an error right away from the KVM_SEV_LAUNCH_UPDATE_VMSA handler if debugging was already enabled. KVM_SET_GUEST_DEBUG are failing already after KVM_SEV_LAUNCH_UPDATE_VMSA is finished due to vcpu->arch.guest_state_protected set to true. Add WARN_ON to kvm_x86::sync_dirty_debug_regs() (saves guest DRs on guest exit) to signify that SEV-ES won't hit that path. Suggested-by: Sean Christopherson Signed-off-by: Alexey Kardashevskiy Link: https://lore.kernel.org/r/20230615063757.3039121-5-aik@amd.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 5 +++++ arch/x86/kvm/svm/svm.c | 9 ++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index d58a25a92aa3f..0299bbe188f16 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -619,6 +619,11 @@ static int __sev_launch_update_vmsa(struct kvm *kvm, struct kvm_vcpu *vcpu, struct vcpu_svm *svm = to_svm(vcpu); int ret; + if (vcpu->guest_debug) { + pr_warn_once("KVM_SET_GUEST_DEBUG for SEV-ES guest is not supported"); + return -EINVAL; + } + /* Perform some pre-encryption checks against the VMSA */ ret = sev_es_sync_vmsa(svm); if (ret) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index a0e803f2a574e..e838cfecc0fa5 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -1983,7 +1983,7 @@ static void svm_sync_dirty_debug_regs(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); - if (vcpu->arch.guest_state_protected) + if (WARN_ON_ONCE(sev_es_guest(vcpu->kvm))) return; get_debugreg(vcpu->arch.db[0], 0); @@ -2714,6 +2714,13 @@ static int dr_interception(struct kvm_vcpu *vcpu) unsigned long val; int err = 0; + /* + * SEV-ES intercepts DR7 only to disable guest debugging and the guest issues a VMGEXIT + * for DR7 write only. KVM cannot change DR7 (always swapped as type 'A') so return early. + */ + if (sev_es_guest(vcpu->kvm)) + return 1; + if (vcpu->guest_debug == 0) { /* * No more DR vmexits; force a reload of the debug registers -- GitLab From c2690b5f01948dfec19d50086312848c0b5b02b0 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Thu, 15 Jun 2023 16:37:53 +1000 Subject: [PATCH 0561/3445] KVM: SVM/SEV/SEV-ES: Rework intercepts Currently SVM setup is done sequentially in init_vmcb() -> sev_init_vmcb() -> sev_es_init_vmcb() and tries keeping SVM/SEV/SEV-ES bits separated. One of the exceptions is DR intercepts which is for SEV-ES before sev_es_init_vmcb() runs. Move the SEV-ES intercept setup to sev_es_init_vmcb(). From now on set_dr_intercepts()/clr_dr_intercepts() handle SVM/SEV only. No functional change intended. Suggested-by: Sean Christopherson Signed-off-by: Alexey Kardashevskiy Reviewed-by: Santosh Shukla Reviewed-by: Tom Lendacky Link: https://lore.kernel.org/r/20230615063757.3039121-6-aik@amd.com [sean: drop comment about intercepting DR7] Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 6 ++++++ arch/x86/kvm/svm/svm.c | 37 ++++++++++++++----------------------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 0299bbe188f16..b3ef509f6fda9 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -2951,6 +2951,7 @@ int sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in) static void sev_es_init_vmcb(struct vcpu_svm *svm) { + struct vmcb *vmcb = svm->vmcb01.ptr; struct kvm_vcpu *vcpu = &svm->vcpu; svm->vmcb->control.nested_ctl |= SVM_NESTED_CTL_SEV_ES_ENABLE; @@ -2979,6 +2980,11 @@ static void sev_es_init_vmcb(struct vcpu_svm *svm) svm_set_intercept(svm, TRAP_CR4_WRITE); svm_set_intercept(svm, TRAP_CR8_WRITE); + vmcb->control.intercepts[INTERCEPT_DR] = 0; + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_READ); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_WRITE); + recalc_intercepts(svm); + /* Can't intercept XSETBV, HV can't modify XCR0 directly */ svm_clr_intercept(svm, INTERCEPT_XSETBV); diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index e838cfecc0fa5..8fad9ebb51266 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -681,23 +681,20 @@ static void set_dr_intercepts(struct vcpu_svm *svm) { struct vmcb *vmcb = svm->vmcb01.ptr; - if (!sev_es_guest(svm->vcpu.kvm)) { - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR0_READ); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR1_READ); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR2_READ); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR3_READ); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR4_READ); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR5_READ); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR6_READ); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR0_WRITE); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR1_WRITE); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR2_WRITE); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR3_WRITE); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR4_WRITE); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR5_WRITE); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR6_WRITE); - } - + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR0_READ); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR1_READ); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR2_READ); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR3_READ); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR4_READ); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR5_READ); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR6_READ); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR0_WRITE); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR1_WRITE); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR2_WRITE); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR3_WRITE); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR4_WRITE); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR5_WRITE); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR6_WRITE); vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_READ); vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_WRITE); @@ -710,12 +707,6 @@ static void clr_dr_intercepts(struct vcpu_svm *svm) vmcb->control.intercepts[INTERCEPT_DR] = 0; - /* DR7 access must remain intercepted for an SEV-ES guest */ - if (sev_es_guest(svm->vcpu.kvm)) { - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_READ); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_WRITE); - } - recalc_intercepts(svm); } -- GitLab From d1f85fbe836e61ed330a242f927a98abd98929cc Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Thu, 15 Jun 2023 16:37:54 +1000 Subject: [PATCH 0562/3445] KVM: SEV: Enable data breakpoints in SEV-ES Add support for "DebugSwap for SEV-ES guests", which provides support for swapping DR[0-3] and DR[0-3]_ADDR_MASK on VMRUN and VMEXIT, i.e. allows KVM to expose debug capabilities to SEV-ES guests. Without DebugSwap support, the CPU doesn't save/load most _guest_ debug registers (except DR6/7), and KVM cannot manually context switch guest DRs due the VMSA being encrypted. Enable DebugSwap if and only if the CPU also supports NoNestedDataBp, which causes the CPU to ignore nested #DBs, i.e. #DBs that occur when vectoring a #DB. Without NoNestedDataBp, a malicious guest can DoS the host by putting the CPU into an infinite loop of vectoring #DBs (see https://bugzilla.redhat.com/show_bug.cgi?id=1278496) Set the features bit in sev_es_sync_vmsa() which is the last point when VMSA is not encrypted yet as sev_(es_)init_vmcb() (where the most init happens) is called not only when VCPU is initialised but also on intrahost migration when VMSA is encrypted. Eliminate DR7 intercepts as KVM can't modify guest DR7, and intercepting DR7 would completely defeat the purpose of enabling DebugSwap. Make X86_FEATURE_DEBUG_SWAP appear in /proc/cpuinfo (by not adding "") to let the operator know if the VM can debug. Signed-off-by: Alexey Kardashevskiy Link: https://lore.kernel.org/r/20230615063757.3039121-7-aik@amd.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/include/asm/svm.h | 1 + arch/x86/kvm/svm/sev.c | 36 ++++++++++++++++++++++-- tools/arch/x86/include/asm/cpufeatures.h | 1 + 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index cb8ca46213bed..31c862d79fae2 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -434,6 +434,7 @@ #define X86_FEATURE_SEV_ES (19*32+ 3) /* AMD Secure Encrypted Virtualization - Encrypted State */ #define X86_FEATURE_V_TSC_AUX (19*32+ 9) /* "" Virtual TSC_AUX */ #define X86_FEATURE_SME_COHERENT (19*32+10) /* "" AMD hardware-enforced cache coherency */ +#define X86_FEATURE_DEBUG_SWAP (19*32+14) /* AMD SEV-ES full debug state swap support */ /* AMD-defined Extended Feature 2 EAX, CPUID level 0x80000021 (EAX), word 20 */ #define X86_FEATURE_NO_NESTED_DATA_BP (20*32+ 0) /* "" No Nested Data Breakpoints */ diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h index e7c7379d6ac7b..72ebd5e4e9751 100644 --- a/arch/x86/include/asm/svm.h +++ b/arch/x86/include/asm/svm.h @@ -288,6 +288,7 @@ static_assert((X2AVIC_MAX_PHYSICAL_ID & AVIC_PHYSICAL_MAX_INDEX_MASK) == X2AVIC_ #define AVIC_HPA_MASK ~((0xFFFULL << 52) | 0xFFF) +#define SVM_SEV_FEAT_DEBUG_SWAP BIT(5) struct vmcb_seg { u16 selector; diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index b3ef509f6fda9..b7cd0cc4a19cd 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "mmu.h" #include "x86.h" @@ -54,9 +55,14 @@ module_param_named(sev, sev_enabled, bool, 0444); /* enable/disable SEV-ES support */ static bool sev_es_enabled = true; module_param_named(sev_es, sev_es_enabled, bool, 0444); + +/* enable/disable SEV-ES DebugSwap support */ +static bool sev_es_debug_swap_enabled = true; +module_param_named(debug_swap, sev_es_debug_swap_enabled, bool, 0444); #else #define sev_enabled false #define sev_es_enabled false +#define sev_es_debug_swap_enabled false #endif /* CONFIG_KVM_AMD_SEV */ static u8 sev_enc_bit; @@ -606,6 +612,9 @@ static int sev_es_sync_vmsa(struct vcpu_svm *svm) save->xss = svm->vcpu.arch.ia32_xss; save->dr6 = svm->vcpu.arch.dr6; + if (sev_es_debug_swap_enabled) + save->sev_features |= SVM_SEV_FEAT_DEBUG_SWAP; + pr_debug("Virtual Machine Save Area (VMSA):\n"); print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, save, sizeof(*save), false); @@ -2261,6 +2270,9 @@ out: sev_enabled = sev_supported; sev_es_enabled = sev_es_supported; + if (!sev_es_enabled || !cpu_feature_enabled(X86_FEATURE_DEBUG_SWAP) || + !cpu_feature_enabled(X86_FEATURE_NO_NESTED_DATA_BP)) + sev_es_debug_swap_enabled = false; #endif } @@ -2981,9 +2993,11 @@ static void sev_es_init_vmcb(struct vcpu_svm *svm) svm_set_intercept(svm, TRAP_CR8_WRITE); vmcb->control.intercepts[INTERCEPT_DR] = 0; - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_READ); - vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_WRITE); - recalc_intercepts(svm); + if (!sev_es_debug_swap_enabled) { + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_READ); + vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_WRITE); + recalc_intercepts(svm); + } /* Can't intercept XSETBV, HV can't modify XCR0 directly */ svm_clr_intercept(svm, INTERCEPT_XSETBV); @@ -3053,6 +3067,22 @@ void sev_es_prepare_switch_to_guest(struct sev_es_save_area *hostsa) hostsa->xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK); hostsa->pkru = read_pkru(); hostsa->xss = host_xss; + + /* + * If DebugSwap is enabled, debug registers are loaded but NOT saved by + * the CPU (Type-B). If DebugSwap is disabled/unsupported, the CPU both + * saves and loads debug registers (Type-A). + */ + if (sev_es_debug_swap_enabled) { + hostsa->dr0 = native_get_debugreg(0); + hostsa->dr1 = native_get_debugreg(1); + hostsa->dr2 = native_get_debugreg(2); + hostsa->dr3 = native_get_debugreg(3); + hostsa->dr0_addr_mask = amd_get_dr_addr_mask(0); + hostsa->dr1_addr_mask = amd_get_dr_addr_mask(1); + hostsa->dr2_addr_mask = amd_get_dr_addr_mask(2); + hostsa->dr3_addr_mask = amd_get_dr_addr_mask(3); + } } void sev_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector) diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index cb8ca46213bed..31c862d79fae2 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h @@ -434,6 +434,7 @@ #define X86_FEATURE_SEV_ES (19*32+ 3) /* AMD Secure Encrypted Virtualization - Encrypted State */ #define X86_FEATURE_V_TSC_AUX (19*32+ 9) /* "" Virtual TSC_AUX */ #define X86_FEATURE_SME_COHERENT (19*32+10) /* "" AMD hardware-enforced cache coherency */ +#define X86_FEATURE_DEBUG_SWAP (19*32+14) /* AMD SEV-ES full debug state swap support */ /* AMD-defined Extended Feature 2 EAX, CPUID level 0x80000021 (EAX), word 20 */ #define X86_FEATURE_NO_NESTED_DATA_BP (20*32+ 0) /* "" No Nested Data Breakpoints */ -- GitLab From 90cbf6d914ad7856ca1145dee02babb9eab7bec1 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Thu, 15 Jun 2023 16:37:55 +1000 Subject: [PATCH 0563/3445] KVM: SEV-ES: Eliminate #DB intercept when DebugSwap enabled Disable #DB for SEV-ES guests when DebugSwap is enabled. There is no point in such intercept as KVM does not allow guest debug for SEV-ES guests. Signed-off-by: Alexey Kardashevskiy Link: https://lore.kernel.org/r/20230615063757.3039121-8-aik@amd.com [sean: add comment as to why KVM disables #DB intercept iff DebugSwap=1] Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index b7cd0cc4a19cd..b35cd670ce667 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -2997,6 +2997,17 @@ static void sev_es_init_vmcb(struct vcpu_svm *svm) vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_READ); vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_WRITE); recalc_intercepts(svm); + } else { + /* + * Disable #DB intercept iff DebugSwap is enabled. KVM doesn't + * allow debugging SEV-ES guests, and enables DebugSwap iff + * NO_NESTED_DATA_BP is supported, so there's no reason to + * intercept #DB when DebugSwap is enabled. For simplicity + * with respect to guest debug, intercept #DB for other VMs + * even if NO_NESTED_DATA_BP is supported, i.e. even if the + * guest can't DoS the CPU with infinite #DB vectoring. + */ + clr_exception_intercept(svm, DB_VECTOR); } /* Can't intercept XSETBV, HV can't modify XCR0 directly */ -- GitLab From 389fbbec261b2842fd0e34b26a2b288b122cc406 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 15 Jun 2023 16:37:56 +1000 Subject: [PATCH 0564/3445] KVM: SVM: Don't defer NMI unblocking until next exit for SEV-ES guests Immediately mark NMIs as unmasked in response to #VMGEXIT(NMI complete) instead of setting awaiting_iret_completion and waiting until the *next* VM-Exit to unmask NMIs. The whole point of "NMI complete" is that the guest is responsible for telling the hypervisor when it's safe to inject an NMI, i.e. there's no need to wait. And because there's no IRET to single-step, the next VM-Exit could be a long time coming, i.e. KVM could incorrectly hold an NMI pending for far longer than what is required and expected. Opportunistically fix a stale reference to HF_IRET_MASK. Fixes: 916b54a7688b ("KVM: x86: Move HF_NMI_MASK and HF_IRET_MASK into "struct vcpu_svm"") Fixes: 4444dfe4050b ("KVM: SVM: Add NMI support for an SEV-ES guest") Cc: Tom Lendacky Link: https://lore.kernel.org/r/20230615063757.3039121-9-aik@amd.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 5 ++++- arch/x86/kvm/svm/svm.c | 10 +++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index b35cd670ce667..2cd15783dfb94 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -2900,7 +2900,10 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu) svm->sev_es.ghcb_sa); break; case SVM_VMGEXIT_NMI_COMPLETE: - ret = svm_invoke_exit_handler(vcpu, SVM_EXIT_IRET); + ++vcpu->stat.nmi_window_exits; + svm->nmi_masked = false; + kvm_make_request(KVM_REQ_EVENT, vcpu); + ret = 1; break; case SVM_VMGEXIT_AP_HLT_LOOP: ret = kvm_emulate_ap_reset_hold(vcpu); diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 8fad9ebb51266..b15bc158ecc68 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -2535,12 +2535,13 @@ static int iret_interception(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); + WARN_ON_ONCE(sev_es_guest(vcpu->kvm)); + ++vcpu->stat.nmi_window_exits; svm->awaiting_iret_completion = true; svm_clr_iret_intercept(svm); - if (!sev_es_guest(vcpu->kvm)) - svm->nmi_iret_rip = kvm_rip_read(vcpu); + svm->nmi_iret_rip = kvm_rip_read(vcpu); kvm_make_request(KVM_REQ_EVENT, vcpu); return 1; @@ -3950,12 +3951,11 @@ static void svm_complete_interrupts(struct kvm_vcpu *vcpu) svm->soft_int_injected = false; /* - * If we've made progress since setting HF_IRET_MASK, we've + * If we've made progress since setting awaiting_iret_completion, we've * executed an IRET and can allow NMI injection. */ if (svm->awaiting_iret_completion && - (sev_es_guest(vcpu->kvm) || - kvm_rip_read(vcpu) != svm->nmi_iret_rip)) { + kvm_rip_read(vcpu) != svm->nmi_iret_rip) { svm->awaiting_iret_completion = false; svm->nmi_masked = false; kvm_make_request(KVM_REQ_EVENT, vcpu); -- GitLab From a6bb5709029756a6151afed0eec26ba2bfabed51 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 15 Jun 2023 16:37:57 +1000 Subject: [PATCH 0565/3445] KVM: SVM: Don't try to pointlessly single-step SEV-ES guests for NMI window Bail early from svm_enable_nmi_window() for SEV-ES guests without trying to enable single-step of the guest, as single-stepping an SEV-ES guest is impossible and the guest is responsible for *telling* KVM when it is ready for an new NMI to be injected. Functionally, setting TF and RF in svm->vmcb->save.rflags is benign as the field is ignored by hardware, but it's all kinds of confusing. Signed-off-by: Alexey Kardashevskiy Link: https://lore.kernel.org/r/20230615063757.3039121-10-aik@amd.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/svm.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index b15bc158ecc68..1bc0936bbd514 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -3802,6 +3802,19 @@ static void svm_enable_nmi_window(struct kvm_vcpu *vcpu) if (svm_get_nmi_mask(vcpu) && !svm->awaiting_iret_completion) return; /* IRET will cause a vm exit */ + /* + * SEV-ES guests are responsible for signaling when a vCPU is ready to + * receive a new NMI, as SEV-ES guests can't be single-stepped, i.e. + * KVM can't intercept and single-step IRET to detect when NMIs are + * unblocked (architecturally speaking). See SVM_VMGEXIT_NMI_COMPLETE. + * + * Note, GIF is guaranteed to be '1' for SEV-ES guests as hardware + * ignores SEV-ES guest writes to EFER.SVME *and* CLGI/STGI are not + * supported NAEs in the GHCB protocol. + */ + if (sev_es_guest(vcpu->kvm)) + return; + if (!gif_set(svm)) { if (vgif) svm_set_intercept(svm, INTERCEPT_STGI); -- GitLab From f94c3bce7491228733b765e60189aa325b866ff0 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 23 Jul 2023 22:13:39 -0700 Subject: [PATCH 0566/3445] Input: qt2160 - tweak check for i2c adapter functionality i2c_check_functionality() returns essentially a boolean and not an error code, so treat it as such. Link: https://lore.kernel.org/r/20230724051345.335219-1-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/qt2160.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c index 599ea85cfd30c..b0b9d7a2691e6 100644 --- a/drivers/input/keyboard/qt2160.c +++ b/drivers/input/keyboard/qt2160.c @@ -345,12 +345,9 @@ static int qt2160_probe(struct i2c_client *client) int i; int error; - /* Check functionality */ - error = i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_BYTE); - if (!error) { + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) { dev_err(&client->dev, "%s adapter not supported\n", - dev_driver_string(&client->adapter->dev)); + dev_driver_string(&client->adapter->dev)); return -ENODEV; } -- GitLab From f1fbff609a1439df4afedde7663148bffa9d67ea Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 23 Jul 2023 22:13:40 -0700 Subject: [PATCH 0567/3445] Input: qt2160 - switch to using threaded interrupt handler Instead of using combination of normal IRQ and work item which required careful handling on device teardown, use standard threaded interrupt that allows communication wityh the chip over slow (I2C) bus directly in the interrupt handler. To support polling mode switch to standard polling support implemented by the input core. Link: https://lore.kernel.org/r/20230724051345.335219-2-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/qt2160.c | 53 ++++++++++++--------------------- 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c index b0b9d7a2691e6..b8c0f0ebf6041 100644 --- a/drivers/input/keyboard/qt2160.c +++ b/drivers/input/keyboard/qt2160.c @@ -32,7 +32,7 @@ #define QT2160_NUM_LEDS_X 8 -#define QT2160_CYCLE_INTERVAL (2*HZ) +#define QT2160_CYCLE_INTERVAL 2000 /* msec - 2 sec */ static unsigned char qt2160_key2code[] = { KEY_0, KEY_1, KEY_2, KEY_3, @@ -54,7 +54,6 @@ struct qt2160_led { struct qt2160_data { struct i2c_client *client; struct input_dev *input; - struct delayed_work dwork; unsigned short keycodes[ARRAY_SIZE(qt2160_key2code)]; u16 key_matrix; #ifdef CONFIG_LEDS_CLASS @@ -155,10 +154,10 @@ static int qt2160_read_block(struct i2c_client *client, return 0; } -static int qt2160_get_key_matrix(struct qt2160_data *qt2160) +static void qt2160_get_key_matrix(struct input_dev *input) { + struct qt2160_data *qt2160 = input_get_drvdata(input); struct i2c_client *client = qt2160->client; - struct input_dev *input = qt2160->input; u8 regs[6]; u16 old_matrix, new_matrix; int ret, i, mask; @@ -173,7 +172,7 @@ static int qt2160_get_key_matrix(struct qt2160_data *qt2160) if (ret) { dev_err(&client->dev, "could not perform chip read.\n"); - return ret; + return; } old_matrix = qt2160->key_matrix; @@ -191,37 +190,17 @@ static int qt2160_get_key_matrix(struct qt2160_data *qt2160) } input_sync(input); - - return 0; } -static irqreturn_t qt2160_irq(int irq, void *_qt2160) +static irqreturn_t qt2160_irq(int irq, void *data) { - struct qt2160_data *qt2160 = _qt2160; + struct input_dev *input = data; - mod_delayed_work(system_wq, &qt2160->dwork, 0); + qt2160_get_key_matrix(input); return IRQ_HANDLED; } -static void qt2160_schedule_read(struct qt2160_data *qt2160) -{ - schedule_delayed_work(&qt2160->dwork, QT2160_CYCLE_INTERVAL); -} - -static void qt2160_worker(struct work_struct *work) -{ - struct qt2160_data *qt2160 = - container_of(work, struct qt2160_data, dwork.work); - - dev_dbg(&qt2160->client->dev, "worker\n"); - - qt2160_get_key_matrix(qt2160); - - /* Avoid device lock up by checking every so often */ - qt2160_schedule_read(qt2160); -} - static int qt2160_read(struct i2c_client *client, u8 reg) { int ret; @@ -365,7 +344,6 @@ static int qt2160_probe(struct i2c_client *client) qt2160->client = client; qt2160->input = input; - INIT_DELAYED_WORK(&qt2160->dwork, qt2160_worker); input->name = "AT42QT2160 Touch Sense Keyboard"; input->id.bustype = BUS_I2C; @@ -382,6 +360,8 @@ static int qt2160_probe(struct i2c_client *client) } __clear_bit(KEY_RESERVED, input->keybit); + input_set_drvdata(input, qt2160); + /* Calibrate device */ error = qt2160_write(client, QT2160_CMD_CALIBRATE, 1); if (error) { @@ -390,13 +370,21 @@ static int qt2160_probe(struct i2c_client *client) } if (client->irq) { - error = request_irq(client->irq, qt2160_irq, - IRQF_TRIGGER_FALLING, "qt2160", qt2160); + error = request_threaded_irq(client->irq, NULL, qt2160_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "qt2160", input); if (error) { dev_err(&client->dev, "failed to allocate irq %d\n", client->irq); goto err_free_mem; } + } else { + error = input_setup_polling(input, qt2160_get_key_matrix); + if (error) { + dev_err(&client->dev, "Failed to setup polling\n"); + goto err_free_mem; + } + input_set_poll_interval(input, QT2160_CYCLE_INTERVAL); } error = qt2160_register_leds(qt2160); @@ -413,7 +401,6 @@ static int qt2160_probe(struct i2c_client *client) } i2c_set_clientdata(client, qt2160); - qt2160_schedule_read(qt2160); return 0; @@ -438,8 +425,6 @@ static void qt2160_remove(struct i2c_client *client) if (client->irq) free_irq(client->irq, qt2160); - cancel_delayed_work_sync(&qt2160->dwork); - input_unregister_device(qt2160->input); kfree(qt2160); } -- GitLab From d675c9b573dd23714c5d3fee64c834bc459d626a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 23 Jul 2023 22:13:41 -0700 Subject: [PATCH 0568/3445] Input: qt2160 - do not hard code interrupt trigger Rely on the platform and ACPI/DT to set up the interrupt trigger. Link: https://lore.kernel.org/r/20230724051345.335219-3-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/qt2160.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c index b8c0f0ebf6041..6cfaabd104822 100644 --- a/drivers/input/keyboard/qt2160.c +++ b/drivers/input/keyboard/qt2160.c @@ -371,8 +371,7 @@ static int qt2160_probe(struct i2c_client *client) if (client->irq) { error = request_threaded_irq(client->irq, NULL, qt2160_irq, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - "qt2160", input); + IRQF_ONESHOT, "qt2160", input); if (error) { dev_err(&client->dev, "failed to allocate irq %d\n", client->irq); -- GitLab From 3e4bb047b23375a34dbf5885709ac3729d9cfb22 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 23 Jul 2023 22:13:42 -0700 Subject: [PATCH 0569/3445] Input: qt2160 - convert to use devm_* api Use devm_* api to simplify code, this makes it unnecessary to explicitly release resources. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230714080611.81302-7-frank.li@vivo.com Link: https://lore.kernel.org/r/20230724051345.335219-4-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/qt2160.c | 77 +++++++++------------------------ 1 file changed, 20 insertions(+), 57 deletions(-) diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c index 6cfaabd104822..7e3b09642ab75 100644 --- a/drivers/input/keyboard/qt2160.c +++ b/drivers/input/keyboard/qt2160.c @@ -239,7 +239,7 @@ static int qt2160_write(struct i2c_client *client, u8 reg, u8 data) static int qt2160_register_leds(struct qt2160_data *qt2160) { struct i2c_client *client = qt2160->client; - int ret; + int error; int i; for (i = 0; i < QT2160_NUM_LEDS_X; i++) { @@ -252,9 +252,9 @@ static int qt2160_register_leds(struct qt2160_data *qt2160) led->id = i; led->qt2160 = qt2160; - ret = led_classdev_register(&client->dev, &led->cdev); - if (ret < 0) - return ret; + error = devm_led_classdev_register(&client->dev, &led->cdev); + if (error) + return error; } /* Tur off LEDs */ @@ -265,14 +265,6 @@ static int qt2160_register_leds(struct qt2160_data *qt2160) return 0; } -static void qt2160_unregister_leds(struct qt2160_data *qt2160) -{ - int i; - - for (i = 0; i < QT2160_NUM_LEDS_X; i++) - led_classdev_unregister(&qt2160->leds[i].cdev); -} - #else static inline int qt2160_register_leds(struct qt2160_data *qt2160) @@ -280,10 +272,6 @@ static inline int qt2160_register_leds(struct qt2160_data *qt2160) return 0; } -static inline void qt2160_unregister_leds(struct qt2160_data *qt2160) -{ -} - #endif static bool qt2160_identify(struct i2c_client *client) @@ -334,13 +322,13 @@ static int qt2160_probe(struct i2c_client *client) return -ENODEV; /* Chip is valid and active. Allocate structure */ - qt2160 = kzalloc(sizeof(struct qt2160_data), GFP_KERNEL); - input = input_allocate_device(); - if (!qt2160 || !input) { - dev_err(&client->dev, "insufficient memory\n"); - error = -ENOMEM; - goto err_free_mem; - } + qt2160 = devm_kzalloc(&client->dev, sizeof(*qt2160), GFP_KERNEL); + if (!qt2160) + return -ENOMEM; + + input = devm_input_allocate_device(&client->dev); + if (!input) + return -ENOMEM; qt2160->client = client; qt2160->input = input; @@ -366,22 +354,24 @@ static int qt2160_probe(struct i2c_client *client) error = qt2160_write(client, QT2160_CMD_CALIBRATE, 1); if (error) { dev_err(&client->dev, "failed to calibrate device\n"); - goto err_free_mem; + return error; } if (client->irq) { - error = request_threaded_irq(client->irq, NULL, qt2160_irq, - IRQF_ONESHOT, "qt2160", input); + error = devm_request_threaded_irq(&client->dev, client->irq, + NULL, qt2160_irq, + IRQF_ONESHOT, + "qt2160", input); if (error) { dev_err(&client->dev, "failed to allocate irq %d\n", client->irq); - goto err_free_mem; + return error; } } else { error = input_setup_polling(input, qt2160_get_key_matrix); if (error) { dev_err(&client->dev, "Failed to setup polling\n"); - goto err_free_mem; + return error; } input_set_poll_interval(input, QT2160_CYCLE_INTERVAL); } @@ -389,43 +379,17 @@ static int qt2160_probe(struct i2c_client *client) error = qt2160_register_leds(qt2160); if (error) { dev_err(&client->dev, "Failed to register leds\n"); - goto err_free_irq; + return error; } error = input_register_device(qt2160->input); if (error) { dev_err(&client->dev, "Failed to register input device\n"); - goto err_unregister_leds; + return error; } - i2c_set_clientdata(client, qt2160); - return 0; - -err_unregister_leds: - qt2160_unregister_leds(qt2160); -err_free_irq: - if (client->irq) - free_irq(client->irq, qt2160); -err_free_mem: - input_free_device(input); - kfree(qt2160); - return error; -} - -static void qt2160_remove(struct i2c_client *client) -{ - struct qt2160_data *qt2160 = i2c_get_clientdata(client); - - qt2160_unregister_leds(qt2160); - - /* Release IRQ so no queue will be scheduled */ - if (client->irq) - free_irq(client->irq, qt2160); - - input_unregister_device(qt2160->input); - kfree(qt2160); } static const struct i2c_device_id qt2160_idtable[] = { @@ -442,7 +406,6 @@ static struct i2c_driver qt2160_driver = { .id_table = qt2160_idtable, .probe = qt2160_probe, - .remove = qt2160_remove, }; module_i2c_driver(qt2160_driver); -- GitLab From 0410595e23f8eb801301ee3e44597d3a780b6285 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 23 Jul 2023 22:28:59 -0700 Subject: [PATCH 0570/3445] Input: lm8323 - rely on device core to create kp_disable attribute Device core now has facilities to create driver-specific device attributes as part of driver probing, use them. Link: https://lore.kernel.org/r/20230724052901.350240-1-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/lm8323.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index 3964f6e0f6afa..d5195415533a1 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -615,6 +615,12 @@ static ssize_t lm8323_set_disable(struct device *dev, } static DEVICE_ATTR(disable_kp, 0644, lm8323_show_disable, lm8323_set_disable); +static struct attribute *lm8323_attrs[] = { + &dev_attr_disable_kp.attr, + NULL, +}; +ATTRIBUTE_GROUPS(lm8323); + static int lm8323_probe(struct i2c_client *client) { struct lm8323_platform_data *pdata = dev_get_platdata(&client->dev); @@ -696,9 +702,6 @@ static int lm8323_probe(struct i2c_client *client) } lm->kp_enabled = true; - err = device_create_file(&client->dev, &dev_attr_disable_kp); - if (err < 0) - goto fail2; idev->name = pdata->name ? : "LM8323 keypad"; snprintf(lm->phys, sizeof(lm->phys), @@ -719,14 +722,14 @@ static int lm8323_probe(struct i2c_client *client) err = input_register_device(idev); if (err) { dev_dbg(&client->dev, "error registering input device\n"); - goto fail3; + goto fail2; } err = request_threaded_irq(client->irq, NULL, lm8323_irq, IRQF_TRIGGER_LOW|IRQF_ONESHOT, "lm8323", lm); if (err) { dev_err(&client->dev, "could not get IRQ %d\n", client->irq); - goto fail4; + goto fail3; } i2c_set_clientdata(client, lm); @@ -736,11 +739,9 @@ static int lm8323_probe(struct i2c_client *client) return 0; -fail4: +fail3: input_unregister_device(idev); idev = NULL; -fail3: - device_remove_file(&client->dev, &dev_attr_disable_kp); fail2: while (--pwm >= 0) if (lm->pwm[pwm].enabled) @@ -761,8 +762,6 @@ static void lm8323_remove(struct i2c_client *client) input_unregister_device(lm->idev); - device_remove_file(&lm->client->dev, &dev_attr_disable_kp); - for (i = 0; i < 3; i++) if (lm->pwm[i].enabled) led_classdev_unregister(&lm->pwm[i].cdev); @@ -823,8 +822,9 @@ static const struct i2c_device_id lm8323_id[] = { static struct i2c_driver lm8323_i2c_driver = { .driver = { - .name = "lm8323", - .pm = pm_sleep_ptr(&lm8323_pm_ops), + .name = "lm8323", + .pm = pm_sleep_ptr(&lm8323_pm_ops), + .dev_groups = lm8323_groups, }, .probe = lm8323_probe, .remove = lm8323_remove, -- GitLab From fe45d12745d61fd333e56c1c25c060350a520a39 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 23 Jul 2023 22:29:00 -0700 Subject: [PATCH 0571/3445] Input: lm8323 - convert to use devm_* api Use devm_* api to simplify code, this makes it unnecessary to explicitly release resources. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230724052901.350240-2-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/lm8323.c | 77 +++++++++++---------------------- 1 file changed, 26 insertions(+), 51 deletions(-) diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index d5195415533a1..7bee93e9b0f5e 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -556,6 +556,7 @@ static int init_pwm(struct lm8323_chip *lm, int id, struct device *dev, const char *name) { struct lm8323_pwm *pwm; + int err; BUG_ON(id > 3); @@ -575,9 +576,11 @@ static int init_pwm(struct lm8323_chip *lm, int id, struct device *dev, pwm->cdev.name = name; pwm->cdev.brightness_set = lm8323_pwm_set_brightness; pwm->cdev.groups = lm8323_pwm_groups; - if (led_classdev_register(dev, &pwm->cdev) < 0) { - dev_err(dev, "couldn't register PWM %d\n", id); - return -1; + + err = devm_led_classdev_register(dev, &pwm->cdev); + if (err) { + dev_err(dev, "couldn't register PWM %d: %d\n", id, err); + return err; } pwm->enabled = true; } @@ -585,8 +588,6 @@ static int init_pwm(struct lm8323_chip *lm, int id, struct device *dev, return 0; } -static struct i2c_driver lm8323_i2c_driver; - static ssize_t lm8323_show_disable(struct device *dev, struct device_attribute *attr, char *buf) { @@ -648,12 +649,13 @@ static int lm8323_probe(struct i2c_client *client) return -EINVAL; } - lm = kzalloc(sizeof *lm, GFP_KERNEL); - idev = input_allocate_device(); - if (!lm || !idev) { - err = -ENOMEM; - goto fail1; - } + lm = devm_kzalloc(&client->dev, sizeof(*lm), GFP_KERNEL); + if (!lm) + return -ENOMEM; + + idev = devm_input_allocate_device(&client->dev); + if (!idev) + return -ENOMEM; lm->client = client; lm->idev = idev; @@ -669,8 +671,10 @@ static int lm8323_probe(struct i2c_client *client) lm8323_reset(lm); - /* Nothing's set up to service the IRQ yet, so just spin for max. - * 100ms until we can configure. */ + /* + * Nothing's set up to service the IRQ yet, so just spin for max. + * 100ms until we can configure. + */ tmo = jiffies + msecs_to_jiffies(100); while (lm8323_read(lm, LM8323_CMD_READ_INT, data, 1) == 1) { if (data[0] & INT_NOINIT) @@ -690,15 +694,14 @@ static int lm8323_probe(struct i2c_client *client) /* If a true probe check the device */ if (lm8323_read_id(lm, data) != 0) { dev_err(&client->dev, "device not found\n"); - err = -ENODEV; - goto fail1; + return -ENODEV; } for (pwm = 0; pwm < LM8323_NUM_PWMS; pwm++) { err = init_pwm(lm, pwm + 1, &client->dev, pdata->pwm_names[pwm]); - if (err < 0) - goto fail2; + if (err) + return err; } lm->kp_enabled = true; @@ -722,14 +725,16 @@ static int lm8323_probe(struct i2c_client *client) err = input_register_device(idev); if (err) { dev_dbg(&client->dev, "error registering input device\n"); - goto fail2; + return err; } - err = request_threaded_irq(client->irq, NULL, lm8323_irq, - IRQF_TRIGGER_LOW|IRQF_ONESHOT, "lm8323", lm); + err = devm_request_threaded_irq(&client->dev, client->irq, + NULL, lm8323_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "lm8323", lm); if (err) { dev_err(&client->dev, "could not get IRQ %d\n", client->irq); - goto fail3; + return err; } i2c_set_clientdata(client, lm); @@ -738,35 +743,6 @@ static int lm8323_probe(struct i2c_client *client) enable_irq_wake(client->irq); return 0; - -fail3: - input_unregister_device(idev); - idev = NULL; -fail2: - while (--pwm >= 0) - if (lm->pwm[pwm].enabled) - led_classdev_unregister(&lm->pwm[pwm].cdev); -fail1: - input_free_device(idev); - kfree(lm); - return err; -} - -static void lm8323_remove(struct i2c_client *client) -{ - struct lm8323_chip *lm = i2c_get_clientdata(client); - int i; - - disable_irq_wake(client->irq); - free_irq(client->irq, lm); - - input_unregister_device(lm->idev); - - for (i = 0; i < 3; i++) - if (lm->pwm[i].enabled) - led_classdev_unregister(&lm->pwm[i].cdev); - - kfree(lm); } /* @@ -827,7 +803,6 @@ static struct i2c_driver lm8323_i2c_driver = { .dev_groups = lm8323_groups, }, .probe = lm8323_probe, - .remove = lm8323_remove, .id_table = lm8323_id, }; MODULE_DEVICE_TABLE(i2c, lm8323_id); -- GitLab From 687fe7dfb736b03ab820d172ea5dbfc1ec447135 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 23 Jul 2023 22:30:18 -0700 Subject: [PATCH 0572/3445] Input: tca6416-keypad - always expect proper IRQ number in i2c client Remove option having i2c client contain raw gpio number instead of proper IRQ number. There are no users of this facility in mainline and it will allow cleaning up the driver code with regard to wakeup handling, etc. Link: https://lore.kernel.org/r/20230724053024.352054-1-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tca6416-keypad.c | 27 +++++++++---------------- include/linux/tca6416_keypad.h | 1 - 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c index 2f745cabf4f24..01bc0b8811882 100644 --- a/drivers/input/keyboard/tca6416-keypad.c +++ b/drivers/input/keyboard/tca6416-keypad.c @@ -148,7 +148,7 @@ static int tca6416_keys_open(struct input_dev *dev) if (chip->use_polling) schedule_delayed_work(&chip->dwork, msecs_to_jiffies(100)); else - enable_irq(chip->irqnum); + enable_irq(chip->client->irq); return 0; } @@ -160,7 +160,7 @@ static void tca6416_keys_close(struct input_dev *dev) if (chip->use_polling) cancel_delayed_work_sync(&chip->dwork); else - disable_irq(chip->irqnum); + disable_irq(chip->client->irq); } static int tca6416_setup_registers(struct tca6416_keypad_chip *chip) @@ -266,12 +266,7 @@ static int tca6416_keypad_probe(struct i2c_client *client) goto fail1; if (!chip->use_polling) { - if (pdata->irq_is_gpio) - chip->irqnum = gpio_to_irq(client->irq); - else - chip->irqnum = client->irq; - - error = request_threaded_irq(chip->irqnum, NULL, + error = request_threaded_irq(client->irq, NULL, tca6416_keys_isr, IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_NO_AUTOEN, @@ -279,7 +274,7 @@ static int tca6416_keypad_probe(struct i2c_client *client) if (error) { dev_dbg(&client->dev, "Unable to claim irq %d; error %d\n", - chip->irqnum, error); + client->irq, error); goto fail1; } } @@ -298,8 +293,8 @@ static int tca6416_keypad_probe(struct i2c_client *client) fail2: if (!chip->use_polling) { - free_irq(chip->irqnum, chip); - enable_irq(chip->irqnum); + free_irq(client->irq, chip); + enable_irq(client->irq); } fail1: input_free_device(input); @@ -312,8 +307,8 @@ static void tca6416_keypad_remove(struct i2c_client *client) struct tca6416_keypad_chip *chip = i2c_get_clientdata(client); if (!chip->use_polling) { - free_irq(chip->irqnum, chip); - enable_irq(chip->irqnum); + free_irq(client->irq, chip); + enable_irq(client->irq); } input_unregister_device(chip->input); @@ -323,10 +318,9 @@ static void tca6416_keypad_remove(struct i2c_client *client) static int tca6416_keypad_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - struct tca6416_keypad_chip *chip = i2c_get_clientdata(client); if (device_may_wakeup(dev)) - enable_irq_wake(chip->irqnum); + enable_irq_wake(client->irq); return 0; } @@ -334,10 +328,9 @@ static int tca6416_keypad_suspend(struct device *dev) static int tca6416_keypad_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - struct tca6416_keypad_chip *chip = i2c_get_clientdata(client); if (device_may_wakeup(dev)) - disable_irq_wake(chip->irqnum); + disable_irq_wake(client->irq); return 0; } diff --git a/include/linux/tca6416_keypad.h b/include/linux/tca6416_keypad.h index b0d36a9934ccd..5cf6f6f82aa70 100644 --- a/include/linux/tca6416_keypad.h +++ b/include/linux/tca6416_keypad.h @@ -25,7 +25,6 @@ struct tca6416_keys_platform_data { unsigned int rep:1; /* enable input subsystem auto repeat */ uint16_t pinmask; uint16_t invert; - int irq_is_gpio; int use_polling; /* use polling if Interrupt is not connected*/ }; #endif -- GitLab From d3176b29263aa8211830c77d87a806066c2c178c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 23 Jul 2023 22:30:19 -0700 Subject: [PATCH 0573/3445] Input: tca6416-keypad - rely on I2C core to set up suspend/resume tca6416_keypad_suspend() and tca6416_keypad_resume() only configure device IRQ for wakeup. I2C core already does this by registering interrupt as a wakeup IRQ in case when device is marked as wakeup-enabled, so we can simply remove this code from the driver. Link: https://lore.kernel.org/r/20230724053024.352054-2-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tca6416-keypad.c | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c index 01bc0b8811882..906dffbf171c3 100644 --- a/drivers/input/keyboard/tca6416-keypad.c +++ b/drivers/input/keyboard/tca6416-keypad.c @@ -287,7 +287,6 @@ static int tca6416_keypad_probe(struct i2c_client *client) } i2c_set_clientdata(client, chip); - device_init_wakeup(&client->dev, 1); return 0; @@ -315,33 +314,9 @@ static void tca6416_keypad_remove(struct i2c_client *client) kfree(chip); } -static int tca6416_keypad_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - - if (device_may_wakeup(dev)) - enable_irq_wake(client->irq); - - return 0; -} - -static int tca6416_keypad_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - - if (device_may_wakeup(dev)) - disable_irq_wake(client->irq); - - return 0; -} - -static DEFINE_SIMPLE_DEV_PM_OPS(tca6416_keypad_dev_pm_ops, - tca6416_keypad_suspend, tca6416_keypad_resume); - static struct i2c_driver tca6416_keypad_driver = { .driver = { .name = "tca6416-keypad", - .pm = pm_sleep_ptr(&tca6416_keypad_dev_pm_ops), }, .probe = tca6416_keypad_probe, .remove = tca6416_keypad_remove, -- GitLab From cc141c35af873c6796e043adcb820833bd8ef8c5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 23 Jul 2023 22:30:20 -0700 Subject: [PATCH 0574/3445] Input: tca6416-keypad - fix interrupt enable disbalance The driver has been switched to use IRQF_NO_AUTOEN, but in the error unwinding and remove paths calls to enable_irq() were left in place, which will lead to an incorrect enable counter value. Fixes: bcd9730a04a1 ("Input: move to use request_irq by IRQF_NO_AUTOEN flag") Link: https://lore.kernel.org/r/20230724053024.352054-3-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tca6416-keypad.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c index 906dffbf171c3..21a2f2de4345a 100644 --- a/drivers/input/keyboard/tca6416-keypad.c +++ b/drivers/input/keyboard/tca6416-keypad.c @@ -291,10 +291,8 @@ static int tca6416_keypad_probe(struct i2c_client *client) return 0; fail2: - if (!chip->use_polling) { + if (!chip->use_polling) free_irq(client->irq, chip); - enable_irq(client->irq); - } fail1: input_free_device(input); kfree(chip); @@ -305,10 +303,8 @@ static void tca6416_keypad_remove(struct i2c_client *client) { struct tca6416_keypad_chip *chip = i2c_get_clientdata(client); - if (!chip->use_polling) { + if (!chip->use_polling) free_irq(client->irq, chip); - enable_irq(client->irq); - } input_unregister_device(chip->input); kfree(chip); -- GitLab From 91a4c69052bb660bc818878309d8a777e635a144 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 23 Jul 2023 22:30:21 -0700 Subject: [PATCH 0575/3445] Input: tca6416-keypad - convert to use devm_* api Use devm_* api to simplify code, this makes it unnecessary to explicitly release resources. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230724053024.352054-4-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tca6416-keypad.c | 53 +++++++++---------------- 1 file changed, 18 insertions(+), 35 deletions(-) diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c index 21a2f2de4345a..ff665319791e9 100644 --- a/drivers/input/keyboard/tca6416-keypad.c +++ b/drivers/input/keyboard/tca6416-keypad.c @@ -216,12 +216,15 @@ static int tca6416_keypad_probe(struct i2c_client *client) return -EINVAL; } - chip = kzalloc(struct_size(chip, buttons, pdata->nbuttons), GFP_KERNEL); - input = input_allocate_device(); - if (!chip || !input) { - error = -ENOMEM; - goto fail1; - } + chip = devm_kzalloc(&client->dev, + struct_size(chip, buttons, pdata->nbuttons), + GFP_KERNEL); + if (!chip) + return -ENOMEM; + + input = devm_input_allocate_device(&client->dev); + if (!input) + return -ENOMEM; chip->client = client; chip->input = input; @@ -233,7 +236,6 @@ static int tca6416_keypad_probe(struct i2c_client *client) input->phys = "tca6416-keys/input0"; input->name = client->name; - input->dev.parent = &client->dev; input->open = tca6416_keys_open; input->close = tca6416_keys_close; @@ -263,19 +265,20 @@ static int tca6416_keypad_probe(struct i2c_client *client) */ error = tca6416_setup_registers(chip); if (error) - goto fail1; + return error; if (!chip->use_polling) { - error = request_threaded_irq(client->irq, NULL, - tca6416_keys_isr, - IRQF_TRIGGER_FALLING | - IRQF_ONESHOT | IRQF_NO_AUTOEN, - "tca6416-keypad", chip); + error = devm_request_threaded_irq(&client->dev, client->irq, + NULL, tca6416_keys_isr, + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT | + IRQF_NO_AUTOEN, + "tca6416-keypad", chip); if (error) { dev_dbg(&client->dev, "Unable to claim irq %d; error %d\n", client->irq, error); - goto fail1; + return error; } } @@ -283,31 +286,12 @@ static int tca6416_keypad_probe(struct i2c_client *client) if (error) { dev_dbg(&client->dev, "Unable to register input device, error: %d\n", error); - goto fail2; + return error; } i2c_set_clientdata(client, chip); return 0; - -fail2: - if (!chip->use_polling) - free_irq(client->irq, chip); -fail1: - input_free_device(input); - kfree(chip); - return error; -} - -static void tca6416_keypad_remove(struct i2c_client *client) -{ - struct tca6416_keypad_chip *chip = i2c_get_clientdata(client); - - if (!chip->use_polling) - free_irq(client->irq, chip); - - input_unregister_device(chip->input); - kfree(chip); } static struct i2c_driver tca6416_keypad_driver = { @@ -315,7 +299,6 @@ static struct i2c_driver tca6416_keypad_driver = { .name = "tca6416-keypad", }, .probe = tca6416_keypad_probe, - .remove = tca6416_keypad_remove, .id_table = tca6416_id, }; -- GitLab From 57b0c96f1e34f550ec7c6699e81a6cfce7857159 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 23 Jul 2023 22:30:22 -0700 Subject: [PATCH 0576/3445] Input: tca6416-keypad - switch to using input core's polling features Instead of rolling custom polling implementation use input core facilities. Link: https://lore.kernel.org/r/20230724053024.352054-5-dmitry.torokhov@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tca6416-keypad.c | 48 +++++++++++-------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c index ff665319791e9..8af59ced1ec2e 100644 --- a/drivers/input/keyboard/tca6416-keypad.c +++ b/drivers/input/keyboard/tca6416-keypad.c @@ -24,6 +24,8 @@ #define TCA6416_INVERT 2 #define TCA6416_DIRECTION 3 +#define TCA6416_POLL_INTERVAL 100 /* msec */ + static const struct i2c_device_id tca6416_id[] = { { "tca6416-keys", 16, }, { "tca6408-keys", 8, }, @@ -43,7 +45,6 @@ struct tca6416_keypad_chip { struct i2c_client *client; struct input_dev *input; - struct delayed_work dwork; int io_size; int irqnum; u16 pinmask; @@ -85,9 +86,9 @@ static int tca6416_read_reg(struct tca6416_keypad_chip *chip, int reg, u16 *val) return 0; } -static void tca6416_keys_scan(struct tca6416_keypad_chip *chip) +static void tca6416_keys_scan(struct input_dev *input) { - struct input_dev *input = chip->input; + struct tca6416_keypad_chip *chip = input_get_drvdata(input); u16 reg_val, val; int error, i, pin_index; @@ -122,33 +123,20 @@ static void tca6416_keys_scan(struct tca6416_keypad_chip *chip) */ static irqreturn_t tca6416_keys_isr(int irq, void *dev_id) { - struct tca6416_keypad_chip *chip = dev_id; - - tca6416_keys_scan(chip); + tca6416_keys_scan(dev_id); return IRQ_HANDLED; } -static void tca6416_keys_work_func(struct work_struct *work) -{ - struct tca6416_keypad_chip *chip = - container_of(work, struct tca6416_keypad_chip, dwork.work); - - tca6416_keys_scan(chip); - schedule_delayed_work(&chip->dwork, msecs_to_jiffies(100)); -} - static int tca6416_keys_open(struct input_dev *dev) { struct tca6416_keypad_chip *chip = input_get_drvdata(dev); - /* Get initial device state in case it has switches */ - tca6416_keys_scan(chip); - - if (chip->use_polling) - schedule_delayed_work(&chip->dwork, msecs_to_jiffies(100)); - else + if (!chip->use_polling) { + /* Get initial device state in case it has switches */ + tca6416_keys_scan(dev); enable_irq(chip->client->irq); + } return 0; } @@ -157,9 +145,7 @@ static void tca6416_keys_close(struct input_dev *dev) { struct tca6416_keypad_chip *chip = input_get_drvdata(dev); - if (chip->use_polling) - cancel_delayed_work_sync(&chip->dwork); - else + if (!chip->use_polling) disable_irq(chip->client->irq); } @@ -232,8 +218,6 @@ static int tca6416_keypad_probe(struct i2c_client *client) chip->pinmask = pdata->pinmask; chip->use_polling = pdata->use_polling; - INIT_DELAYED_WORK(&chip->dwork, tca6416_keys_work_func); - input->phys = "tca6416-keys/input0"; input->name = client->name; @@ -267,13 +251,21 @@ static int tca6416_keypad_probe(struct i2c_client *client) if (error) return error; - if (!chip->use_polling) { + if (chip->use_polling) { + error = input_setup_polling(input, tca6416_keys_scan); + if (error) { + dev_err(&client->dev, "Failed to setup polling\n"); + return error; + } + + input_set_poll_interval(input, TCA6416_POLL_INTERVAL); + } else { error = devm_request_threaded_irq(&client->dev, client->irq, NULL, tca6416_keys_isr, IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_NO_AUTOEN, - "tca6416-keypad", chip); + "tca6416-keypad", input); if (error) { dev_dbg(&client->dev, "Unable to claim irq %d; error %d\n", -- GitLab From 063975feedb14386489619084fbb20792b87d21c Mon Sep 17 00:00:00 2001 From: Chandramohan Akula Date: Wed, 26 Jul 2023 07:51:18 -0700 Subject: [PATCH 0577/3445] bnxt_re: Reorganize the resource stats Move the resource stats to a separate stats structure. Signed-off-by: Chandramohan Akula Signed-off-by: Selvin Xavier Link: https://lore.kernel.org/r/1690383081-15033-2-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/bnxt_re.h | 7 ---- drivers/infiniband/hw/bnxt_re/hw_counters.c | 17 ++++----- drivers/infiniband/hw/bnxt_re/hw_counters.h | 11 ++++++ drivers/infiniband/hw/bnxt_re/ib_verbs.c | 40 ++++++++++----------- drivers/infiniband/hw/bnxt_re/main.c | 14 ++++---- 5 files changed, 47 insertions(+), 42 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/bnxt_re.h b/drivers/infiniband/hw/bnxt_re/bnxt_re.h index 2175103d570f2..03a13258b140f 100644 --- a/drivers/infiniband/hw/bnxt_re/bnxt_re.h +++ b/drivers/infiniband/hw/bnxt_re/bnxt_re.h @@ -175,16 +175,9 @@ struct bnxt_re_dev { struct bnxt_qplib_res qplib_res; struct bnxt_qplib_dpi dpi_privileged; - atomic_t qp_count; struct mutex qp_lock; /* protect qp list */ struct list_head qp_list; - atomic_t cq_count; - atomic_t srq_count; - atomic_t mr_count; - atomic_t mw_count; - atomic_t ah_count; - atomic_t pd_count; /* Max of 2 lossless traffic class supported per port */ u16 cosq[2]; diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.c b/drivers/infiniband/hw/bnxt_re/hw_counters.c index 825d512799d90..8310e9a64c13b 100644 --- a/drivers/infiniband/hw/bnxt_re/hw_counters.c +++ b/drivers/infiniband/hw/bnxt_re/hw_counters.c @@ -254,21 +254,22 @@ int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev, u32 port, int index) { struct bnxt_re_dev *rdev = to_bnxt_re_dev(ibdev, ibdev); - struct ctx_hw_stats *hw_stats = NULL; + struct bnxt_re_res_cntrs *res_s = &rdev->stats.res; struct bnxt_qplib_roce_stats *err_s = NULL; + struct ctx_hw_stats *hw_stats = NULL; int rc = 0; hw_stats = rdev->qplib_ctx.stats.dma; if (!port || !stats) return -EINVAL; - stats->value[BNXT_RE_ACTIVE_QP] = atomic_read(&rdev->qp_count); - stats->value[BNXT_RE_ACTIVE_SRQ] = atomic_read(&rdev->srq_count); - stats->value[BNXT_RE_ACTIVE_CQ] = atomic_read(&rdev->cq_count); - stats->value[BNXT_RE_ACTIVE_MR] = atomic_read(&rdev->mr_count); - stats->value[BNXT_RE_ACTIVE_MW] = atomic_read(&rdev->mw_count); - stats->value[BNXT_RE_ACTIVE_PD] = atomic_read(&rdev->pd_count); - stats->value[BNXT_RE_ACTIVE_AH] = atomic_read(&rdev->ah_count); + stats->value[BNXT_RE_ACTIVE_QP] = atomic_read(&res_s->qp_count); + stats->value[BNXT_RE_ACTIVE_SRQ] = atomic_read(&res_s->srq_count); + stats->value[BNXT_RE_ACTIVE_CQ] = atomic_read(&res_s->cq_count); + stats->value[BNXT_RE_ACTIVE_MR] = atomic_read(&res_s->mr_count); + stats->value[BNXT_RE_ACTIVE_MW] = atomic_read(&res_s->mw_count); + stats->value[BNXT_RE_ACTIVE_PD] = atomic_read(&res_s->pd_count); + stats->value[BNXT_RE_ACTIVE_AH] = atomic_read(&res_s->ah_count); if (hw_stats) { stats->value[BNXT_RE_RECOVERABLE_ERRORS] = diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.h b/drivers/infiniband/hw/bnxt_re/hw_counters.h index 7943b2c393e42..4aa6e31f87070 100644 --- a/drivers/infiniband/hw/bnxt_re/hw_counters.h +++ b/drivers/infiniband/hw/bnxt_re/hw_counters.h @@ -113,6 +113,16 @@ enum bnxt_re_hw_stats { #define BNXT_RE_NUM_STD_COUNTERS (BNXT_RE_OUT_OF_SEQ_ERR + 1) +struct bnxt_re_res_cntrs { + atomic_t qp_count; + atomic_t cq_count; + atomic_t srq_count; + atomic_t mr_count; + atomic_t mw_count; + atomic_t ah_count; + atomic_t pd_count; +}; + struct bnxt_re_rstat { struct bnxt_qplib_roce_stats errs; struct bnxt_qplib_ext_stat ext_stat; @@ -120,6 +130,7 @@ struct bnxt_re_rstat { struct bnxt_re_stats { struct bnxt_re_rstat rstat; + struct bnxt_re_res_cntrs res; }; struct rdma_hw_stats *bnxt_re_ib_alloc_hw_port_stats(struct ib_device *ibdev, diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index ec4d163f3f525..b28c869ed8906 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -602,7 +602,7 @@ int bnxt_re_dealloc_pd(struct ib_pd *ib_pd, struct ib_udata *udata) if (!bnxt_qplib_dealloc_pd(&rdev->qplib_res, &rdev->qplib_res.pd_tbl, &pd->qplib_pd)) - atomic_dec(&rdev->pd_count); + atomic_dec(&rdev->stats.res.pd_count); } return 0; } @@ -665,7 +665,7 @@ int bnxt_re_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata) if (bnxt_re_create_fence_mr(pd)) ibdev_warn(&rdev->ibdev, "Failed to create Fence-MR\n"); - atomic_inc(&rdev->pd_count); + atomic_inc(&rdev->stats.res.pd_count); return 0; dbfail: @@ -691,7 +691,7 @@ int bnxt_re_destroy_ah(struct ib_ah *ib_ah, u32 flags) else goto fail; } - atomic_dec(&rdev->ah_count); + atomic_dec(&rdev->stats.res.ah_count); fail: return rc; } @@ -777,7 +777,7 @@ int bnxt_re_create_ah(struct ib_ah *ib_ah, struct rdma_ah_init_attr *init_attr, wmb(); /* make sure cache is updated. */ spin_unlock_irqrestore(&uctx->sh_lock, flag); } - atomic_inc(&rdev->ah_count); + atomic_inc(&rdev->stats.res.ah_count); return 0; } @@ -838,7 +838,7 @@ static int bnxt_re_destroy_gsi_sqp(struct bnxt_re_qp *qp) bnxt_qplib_destroy_ah(&rdev->qplib_res, &gsi_sah->qplib_ah, true); - atomic_dec(&rdev->ah_count); + atomic_dec(&rdev->stats.res.ah_count); bnxt_qplib_clean_qp(&qp->qplib_qp); ibdev_dbg(&rdev->ibdev, "Destroy the shadow QP\n"); @@ -853,7 +853,7 @@ static int bnxt_re_destroy_gsi_sqp(struct bnxt_re_qp *qp) mutex_lock(&rdev->qp_lock); list_del(&gsi_sqp->list); mutex_unlock(&rdev->qp_lock); - atomic_dec(&rdev->qp_count); + atomic_dec(&rdev->stats.res.qp_count); kfree(rdev->gsi_ctx.sqp_tbl); kfree(gsi_sah); @@ -900,7 +900,7 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata) mutex_lock(&rdev->qp_lock); list_del(&qp->list); mutex_unlock(&rdev->qp_lock); - atomic_dec(&rdev->qp_count); + atomic_dec(&rdev->stats.res.qp_count); ib_umem_release(qp->rumem); ib_umem_release(qp->sumem); @@ -1085,7 +1085,7 @@ static struct bnxt_re_ah *bnxt_re_create_shadow_qp_ah "Failed to allocate HW AH for Shadow QP"); goto fail; } - atomic_inc(&rdev->ah_count); + atomic_inc(&rdev->stats.res.ah_count); return ah; @@ -1153,7 +1153,7 @@ static struct bnxt_re_qp *bnxt_re_create_shadow_qp INIT_LIST_HEAD(&qp->list); mutex_lock(&rdev->qp_lock); list_add_tail(&qp->list, &rdev->qp_list); - atomic_inc(&rdev->qp_count); + atomic_inc(&rdev->stats.res.qp_count); mutex_unlock(&rdev->qp_lock); return qp; fail: @@ -1535,7 +1535,7 @@ int bnxt_re_create_qp(struct ib_qp *ib_qp, struct ib_qp_init_attr *qp_init_attr, mutex_lock(&rdev->qp_lock); list_add_tail(&qp->list, &rdev->qp_list); mutex_unlock(&rdev->qp_lock); - atomic_inc(&rdev->qp_count); + atomic_inc(&rdev->stats.res.qp_count); return 0; qp_destroy: @@ -1638,7 +1638,7 @@ int bnxt_re_destroy_srq(struct ib_srq *ib_srq, struct ib_udata *udata) nq = qplib_srq->cq->nq; bnxt_qplib_destroy_srq(&rdev->qplib_res, qplib_srq); ib_umem_release(srq->umem); - atomic_dec(&rdev->srq_count); + atomic_dec(&rdev->stats.res.srq_count); if (nq) nq->budget--; return 0; @@ -1750,7 +1750,7 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq, } if (nq) nq->budget++; - atomic_inc(&rdev->srq_count); + atomic_inc(&rdev->stats.res.srq_count); spin_lock_init(&srq->lock); return 0; @@ -2876,7 +2876,7 @@ int bnxt_re_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata) bnxt_qplib_destroy_cq(&rdev->qplib_res, &cq->qplib_cq); ib_umem_release(cq->umem); - atomic_dec(&rdev->cq_count); + atomic_dec(&rdev->stats.res.cq_count); nq->budget--; kfree(cq->cql); return 0; @@ -2960,7 +2960,7 @@ int bnxt_re_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, cq->cq_period = cq->qplib_cq.period; nq->budget++; - atomic_inc(&rdev->cq_count); + atomic_inc(&rdev->stats.res.cq_count); spin_lock_init(&cq->cq_lock); if (udata) { @@ -3785,7 +3785,7 @@ struct ib_mr *bnxt_re_get_dma_mr(struct ib_pd *ib_pd, int mr_access_flags) if (mr_access_flags & (IB_ACCESS_REMOTE_WRITE | IB_ACCESS_REMOTE_READ | IB_ACCESS_REMOTE_ATOMIC)) mr->ib_mr.rkey = mr->ib_mr.lkey; - atomic_inc(&rdev->mr_count); + atomic_inc(&rdev->stats.res.mr_count); return &mr->ib_mr; @@ -3818,7 +3818,7 @@ int bnxt_re_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata) ib_umem_release(mr->ib_umem); kfree(mr); - atomic_dec(&rdev->mr_count); + atomic_dec(&rdev->stats.res.mr_count); return rc; } @@ -3886,7 +3886,7 @@ struct ib_mr *bnxt_re_alloc_mr(struct ib_pd *ib_pd, enum ib_mr_type type, goto fail_mr; } - atomic_inc(&rdev->mr_count); + atomic_inc(&rdev->stats.res.mr_count); return &mr->ib_mr; fail_mr: @@ -3922,7 +3922,7 @@ struct ib_mw *bnxt_re_alloc_mw(struct ib_pd *ib_pd, enum ib_mw_type type, } mw->ib_mw.rkey = mw->qplib_mw.rkey; - atomic_inc(&rdev->mw_count); + atomic_inc(&rdev->stats.res.mw_count); return &mw->ib_mw; fail: @@ -3943,7 +3943,7 @@ int bnxt_re_dealloc_mw(struct ib_mw *ib_mw) } kfree(mw); - atomic_dec(&rdev->mw_count); + atomic_dec(&rdev->stats.res.mw_count); return rc; } @@ -4010,7 +4010,7 @@ struct ib_mr *bnxt_re_reg_user_mr(struct ib_pd *ib_pd, u64 start, u64 length, mr->ib_mr.lkey = mr->qplib_mr.lkey; mr->ib_mr.rkey = mr->qplib_mr.lkey; - atomic_inc(&rdev->mr_count); + atomic_inc(&rdev->stats.res.mr_count); return &mr->ib_mr; free_umem: diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index 6469811003f6d..91efa0400c594 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -918,13 +918,13 @@ static struct bnxt_re_dev *bnxt_re_dev_add(struct bnxt_aux_priv *aux_priv, rdev->id = rdev->en_dev->pdev->devfn; INIT_LIST_HEAD(&rdev->qp_list); mutex_init(&rdev->qp_lock); - atomic_set(&rdev->qp_count, 0); - atomic_set(&rdev->cq_count, 0); - atomic_set(&rdev->srq_count, 0); - atomic_set(&rdev->mr_count, 0); - atomic_set(&rdev->mw_count, 0); - atomic_set(&rdev->ah_count, 0); - atomic_set(&rdev->pd_count, 0); + atomic_set(&rdev->stats.res.qp_count, 0); + atomic_set(&rdev->stats.res.cq_count, 0); + atomic_set(&rdev->stats.res.srq_count, 0); + atomic_set(&rdev->stats.res.mr_count, 0); + atomic_set(&rdev->stats.res.mw_count, 0); + atomic_set(&rdev->stats.res.ah_count, 0); + atomic_set(&rdev->stats.res.pd_count, 0); rdev->cosq[0] = 0xFFFF; rdev->cosq[1] = 0xFFFF; -- GitLab From cb95709e0dca7a2dee1c168a2100b5fa21ca6205 Mon Sep 17 00:00:00 2001 From: Chandramohan Akula Date: Wed, 26 Jul 2023 07:51:19 -0700 Subject: [PATCH 0578/3445] bnxt_re: Update the hw counters for resource stats Report the additional resource counters which enables better debugging. Includes active RC/UD QPs, Watermark of the resources and a count that indicates the resize cq operations after driver load. Signed-off-by: Chandramohan Akula Signed-off-by: Selvin Xavier Link: https://lore.kernel.org/r/1690383081-15033-3-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/hw_counters.c | 24 +++++++++ drivers/infiniband/hw/bnxt_re/hw_counters.h | 24 +++++++++ drivers/infiniband/hw/bnxt_re/ib_verbs.c | 55 +++++++++++++++++---- 3 files changed, 94 insertions(+), 9 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.c b/drivers/infiniband/hw/bnxt_re/hw_counters.c index 8310e9a64c13b..8598af579ab03 100644 --- a/drivers/infiniband/hw/bnxt_re/hw_counters.c +++ b/drivers/infiniband/hw/bnxt_re/hw_counters.c @@ -61,10 +61,22 @@ static const struct rdma_stat_desc bnxt_re_stat_descs[] = { [BNXT_RE_ACTIVE_PD].name = "active_pds", [BNXT_RE_ACTIVE_AH].name = "active_ahs", [BNXT_RE_ACTIVE_QP].name = "active_qps", + [BNXT_RE_ACTIVE_RC_QP].name = "active_rc_qps", + [BNXT_RE_ACTIVE_UD_QP].name = "active_ud_qps", [BNXT_RE_ACTIVE_SRQ].name = "active_srqs", [BNXT_RE_ACTIVE_CQ].name = "active_cqs", [BNXT_RE_ACTIVE_MR].name = "active_mrs", [BNXT_RE_ACTIVE_MW].name = "active_mws", + [BNXT_RE_WATERMARK_PD].name = "watermark_pds", + [BNXT_RE_WATERMARK_AH].name = "watermark_ahs", + [BNXT_RE_WATERMARK_QP].name = "watermark_qps", + [BNXT_RE_WATERMARK_RC_QP].name = "watermark_rc_qps", + [BNXT_RE_WATERMARK_UD_QP].name = "watermark_ud_qps", + [BNXT_RE_WATERMARK_SRQ].name = "watermark_srqs", + [BNXT_RE_WATERMARK_CQ].name = "watermark_cqs", + [BNXT_RE_WATERMARK_MR].name = "watermark_mrs", + [BNXT_RE_WATERMARK_MW].name = "watermark_mws", + [BNXT_RE_RESIZE_CQ_CNT].name = "resize_cq_cnt", [BNXT_RE_RX_PKTS].name = "rx_pkts", [BNXT_RE_RX_BYTES].name = "rx_bytes", [BNXT_RE_TX_PKTS].name = "tx_pkts", @@ -264,12 +276,24 @@ int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev, return -EINVAL; stats->value[BNXT_RE_ACTIVE_QP] = atomic_read(&res_s->qp_count); + stats->value[BNXT_RE_ACTIVE_RC_QP] = atomic_read(&res_s->rc_qp_count); + stats->value[BNXT_RE_ACTIVE_UD_QP] = atomic_read(&res_s->ud_qp_count); stats->value[BNXT_RE_ACTIVE_SRQ] = atomic_read(&res_s->srq_count); stats->value[BNXT_RE_ACTIVE_CQ] = atomic_read(&res_s->cq_count); stats->value[BNXT_RE_ACTIVE_MR] = atomic_read(&res_s->mr_count); stats->value[BNXT_RE_ACTIVE_MW] = atomic_read(&res_s->mw_count); stats->value[BNXT_RE_ACTIVE_PD] = atomic_read(&res_s->pd_count); stats->value[BNXT_RE_ACTIVE_AH] = atomic_read(&res_s->ah_count); + stats->value[BNXT_RE_WATERMARK_QP] = res_s->qp_watermark; + stats->value[BNXT_RE_WATERMARK_RC_QP] = res_s->rc_qp_watermark; + stats->value[BNXT_RE_WATERMARK_UD_QP] = res_s->ud_qp_watermark; + stats->value[BNXT_RE_WATERMARK_SRQ] = res_s->srq_watermark; + stats->value[BNXT_RE_WATERMARK_CQ] = res_s->cq_watermark; + stats->value[BNXT_RE_WATERMARK_MR] = res_s->mr_watermark; + stats->value[BNXT_RE_WATERMARK_MW] = res_s->mw_watermark; + stats->value[BNXT_RE_WATERMARK_PD] = res_s->pd_watermark; + stats->value[BNXT_RE_WATERMARK_AH] = res_s->ah_watermark; + stats->value[BNXT_RE_RESIZE_CQ_CNT] = atomic_read(&res_s->resize_count); if (hw_stats) { stats->value[BNXT_RE_RECOVERABLE_ERRORS] = diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.h b/drivers/infiniband/hw/bnxt_re/hw_counters.h index 4aa6e31f87070..7231a2b63620d 100644 --- a/drivers/infiniband/hw/bnxt_re/hw_counters.h +++ b/drivers/infiniband/hw/bnxt_re/hw_counters.h @@ -44,10 +44,22 @@ enum bnxt_re_hw_stats { BNXT_RE_ACTIVE_PD, BNXT_RE_ACTIVE_AH, BNXT_RE_ACTIVE_QP, + BNXT_RE_ACTIVE_RC_QP, + BNXT_RE_ACTIVE_UD_QP, BNXT_RE_ACTIVE_SRQ, BNXT_RE_ACTIVE_CQ, BNXT_RE_ACTIVE_MR, BNXT_RE_ACTIVE_MW, + BNXT_RE_WATERMARK_PD, + BNXT_RE_WATERMARK_AH, + BNXT_RE_WATERMARK_QP, + BNXT_RE_WATERMARK_RC_QP, + BNXT_RE_WATERMARK_UD_QP, + BNXT_RE_WATERMARK_SRQ, + BNXT_RE_WATERMARK_CQ, + BNXT_RE_WATERMARK_MR, + BNXT_RE_WATERMARK_MW, + BNXT_RE_RESIZE_CQ_CNT, BNXT_RE_RX_PKTS, BNXT_RE_RX_BYTES, BNXT_RE_TX_PKTS, @@ -115,12 +127,24 @@ enum bnxt_re_hw_stats { struct bnxt_re_res_cntrs { atomic_t qp_count; + atomic_t rc_qp_count; + atomic_t ud_qp_count; atomic_t cq_count; atomic_t srq_count; atomic_t mr_count; atomic_t mw_count; atomic_t ah_count; atomic_t pd_count; + atomic_t resize_count; + u64 qp_watermark; + u64 rc_qp_watermark; + u64 ud_qp_watermark; + u64 cq_watermark; + u64 srq_watermark; + u64 mr_watermark; + u64 mw_watermark; + u64 ah_watermark; + u64 pd_watermark; }; struct bnxt_re_rstat { diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index b28c869ed8906..2b2505ad103d5 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -615,6 +615,7 @@ int bnxt_re_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata) udata, struct bnxt_re_ucontext, ib_uctx); struct bnxt_re_pd *pd = container_of(ibpd, struct bnxt_re_pd, ib_pd); struct bnxt_re_user_mmap_entry *entry = NULL; + u32 active_pds; int rc = 0; pd->rdev = rdev; @@ -665,7 +666,9 @@ int bnxt_re_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata) if (bnxt_re_create_fence_mr(pd)) ibdev_warn(&rdev->ibdev, "Failed to create Fence-MR\n"); - atomic_inc(&rdev->stats.res.pd_count); + active_pds = atomic_inc_return(&rdev->stats.res.pd_count); + if (active_pds > rdev->stats.res.pd_watermark) + rdev->stats.res.pd_watermark = active_pds; return 0; dbfail: @@ -725,6 +728,7 @@ int bnxt_re_create_ah(struct ib_ah *ib_ah, struct rdma_ah_init_attr *init_attr, const struct ib_gid_attr *sgid_attr; struct bnxt_re_gid_ctx *ctx; struct bnxt_re_ah *ah = container_of(ib_ah, struct bnxt_re_ah, ib_ah); + u32 active_ahs; u8 nw_type; int rc; @@ -777,7 +781,9 @@ int bnxt_re_create_ah(struct ib_ah *ib_ah, struct rdma_ah_init_attr *init_attr, wmb(); /* make sure cache is updated. */ spin_unlock_irqrestore(&uctx->sh_lock, flag); } - atomic_inc(&rdev->stats.res.ah_count); + active_ahs = atomic_inc_return(&rdev->stats.res.ah_count); + if (active_ahs > rdev->stats.res.ah_watermark) + rdev->stats.res.ah_watermark = active_ahs; return 0; } @@ -1487,6 +1493,7 @@ int bnxt_re_create_qp(struct ib_qp *ib_qp, struct ib_qp_init_attr *qp_init_attr, struct bnxt_re_dev *rdev = pd->rdev; struct bnxt_qplib_dev_attr *dev_attr = &rdev->dev_attr; struct bnxt_re_qp *qp = container_of(ib_qp, struct bnxt_re_qp, ib_qp); + u32 active_qps; int rc; rc = bnxt_re_test_qp_limits(rdev, qp_init_attr, dev_attr); @@ -1535,7 +1542,18 @@ int bnxt_re_create_qp(struct ib_qp *ib_qp, struct ib_qp_init_attr *qp_init_attr, mutex_lock(&rdev->qp_lock); list_add_tail(&qp->list, &rdev->qp_list); mutex_unlock(&rdev->qp_lock); - atomic_inc(&rdev->stats.res.qp_count); + active_qps = atomic_inc_return(&rdev->stats.res.qp_count); + if (active_qps > rdev->stats.res.qp_watermark) + rdev->stats.res.qp_watermark = active_qps; + if (qp_init_attr->qp_type == IB_QPT_RC) { + active_qps = atomic_inc_return(&rdev->stats.res.rc_qp_count); + if (active_qps > rdev->stats.res.rc_qp_watermark) + rdev->stats.res.rc_qp_watermark = active_qps; + } else if (qp_init_attr->qp_type == IB_QPT_UD) { + active_qps = atomic_inc_return(&rdev->stats.res.ud_qp_count); + if (active_qps > rdev->stats.res.ud_qp_watermark) + rdev->stats.res.ud_qp_watermark = active_qps; + } return 0; qp_destroy: @@ -1686,6 +1704,7 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq, struct bnxt_re_srq *srq; struct bnxt_re_pd *pd; struct ib_pd *ib_pd; + u32 active_srqs; int rc, entries; ib_pd = ib_srq->pd; @@ -1750,7 +1769,9 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq, } if (nq) nq->budget++; - atomic_inc(&rdev->stats.res.srq_count); + active_srqs = atomic_inc_return(&rdev->stats.res.srq_count); + if (active_srqs > rdev->stats.res.srq_watermark) + rdev->stats.res.srq_watermark = active_srqs; spin_lock_init(&srq->lock); return 0; @@ -2892,6 +2913,7 @@ int bnxt_re_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, int cqe = attr->cqe; struct bnxt_qplib_nq *nq = NULL; unsigned int nq_alloc_cnt; + u32 active_cqs; if (attr->flags) return -EOPNOTSUPP; @@ -2960,7 +2982,9 @@ int bnxt_re_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, cq->cq_period = cq->qplib_cq.period; nq->budget++; - atomic_inc(&rdev->stats.res.cq_count); + active_cqs = atomic_inc_return(&rdev->stats.res.cq_count); + if (active_cqs > rdev->stats.res.cq_watermark) + rdev->stats.res.cq_watermark = active_cqs; spin_lock_init(&cq->cq_lock); if (udata) { @@ -3073,6 +3097,7 @@ int bnxt_re_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) } cq->ib_cq.cqe = cq->resize_cqe; + atomic_inc(&rdev->stats.res.resize_count); return 0; @@ -3758,6 +3783,7 @@ struct ib_mr *bnxt_re_get_dma_mr(struct ib_pd *ib_pd, int mr_access_flags) struct bnxt_re_pd *pd = container_of(ib_pd, struct bnxt_re_pd, ib_pd); struct bnxt_re_dev *rdev = pd->rdev; struct bnxt_re_mr *mr; + u32 active_mrs; int rc; mr = kzalloc(sizeof(*mr), GFP_KERNEL); @@ -3785,7 +3811,9 @@ struct ib_mr *bnxt_re_get_dma_mr(struct ib_pd *ib_pd, int mr_access_flags) if (mr_access_flags & (IB_ACCESS_REMOTE_WRITE | IB_ACCESS_REMOTE_READ | IB_ACCESS_REMOTE_ATOMIC)) mr->ib_mr.rkey = mr->ib_mr.lkey; - atomic_inc(&rdev->stats.res.mr_count); + active_mrs = atomic_inc_return(&rdev->stats.res.mr_count); + if (active_mrs > rdev->stats.res.mr_watermark) + rdev->stats.res.mr_watermark = active_mrs; return &mr->ib_mr; @@ -3848,6 +3876,7 @@ struct ib_mr *bnxt_re_alloc_mr(struct ib_pd *ib_pd, enum ib_mr_type type, struct bnxt_re_pd *pd = container_of(ib_pd, struct bnxt_re_pd, ib_pd); struct bnxt_re_dev *rdev = pd->rdev; struct bnxt_re_mr *mr = NULL; + u32 active_mrs; int rc; if (type != IB_MR_TYPE_MEM_REG) { @@ -3886,7 +3915,9 @@ struct ib_mr *bnxt_re_alloc_mr(struct ib_pd *ib_pd, enum ib_mr_type type, goto fail_mr; } - atomic_inc(&rdev->stats.res.mr_count); + active_mrs = atomic_inc_return(&rdev->stats.res.mr_count); + if (active_mrs > rdev->stats.res.mr_watermark) + rdev->stats.res.mr_watermark = active_mrs; return &mr->ib_mr; fail_mr: @@ -3904,6 +3935,7 @@ struct ib_mw *bnxt_re_alloc_mw(struct ib_pd *ib_pd, enum ib_mw_type type, struct bnxt_re_pd *pd = container_of(ib_pd, struct bnxt_re_pd, ib_pd); struct bnxt_re_dev *rdev = pd->rdev; struct bnxt_re_mw *mw; + u32 active_mws; int rc; mw = kzalloc(sizeof(*mw), GFP_KERNEL); @@ -3922,7 +3954,9 @@ struct ib_mw *bnxt_re_alloc_mw(struct ib_pd *ib_pd, enum ib_mw_type type, } mw->ib_mw.rkey = mw->qplib_mw.rkey; - atomic_inc(&rdev->stats.res.mw_count); + active_mws = atomic_inc_return(&rdev->stats.res.mw_count); + if (active_mws > rdev->stats.res.mw_watermark) + rdev->stats.res.mw_watermark = active_mws; return &mw->ib_mw; fail: @@ -3958,6 +3992,7 @@ struct ib_mr *bnxt_re_reg_user_mr(struct ib_pd *ib_pd, u64 start, u64 length, struct ib_umem *umem; unsigned long page_size; int umem_pgs, rc; + u32 active_mrs; if (length > BNXT_RE_MAX_MR_SIZE) { ibdev_err(&rdev->ibdev, "MR Size: %lld > Max supported:%lld\n", @@ -4010,7 +4045,9 @@ struct ib_mr *bnxt_re_reg_user_mr(struct ib_pd *ib_pd, u64 start, u64 length, mr->ib_mr.lkey = mr->qplib_mr.lkey; mr->ib_mr.rkey = mr->qplib_mr.lkey; - atomic_inc(&rdev->stats.res.mr_count); + active_mrs = atomic_inc_return(&rdev->stats.res.mr_count); + if (active_mrs > rdev->stats.res.mr_watermark) + rdev->stats.res.mr_watermark = active_mrs; return &mr->ib_mr; free_umem: -- GitLab From 4405baf85a83eda03065cf5ddd5de41d7bd1881b Mon Sep 17 00:00:00 2001 From: Chandramohan Akula Date: Wed, 26 Jul 2023 07:51:20 -0700 Subject: [PATCH 0579/3445] bnxt_re: Expose the missing hw counters Add code to expose some of the HW counters related to tx/rx data and Congestion control. Signed-off-by: Chandramohan Akula Signed-off-by: Selvin Xavier Link: https://lore.kernel.org/r/1690383081-15033-4-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/hw_counters.c | 25 +++++++++++++++++++-- drivers/infiniband/hw/bnxt_re/hw_counters.h | 9 ++++++++ drivers/infiniband/hw/bnxt_re/qplib_sp.c | 7 ++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.c b/drivers/infiniband/hw/bnxt_re/hw_counters.c index 8598af579ab03..e50a1cb1984b4 100644 --- a/drivers/infiniband/hw/bnxt_re/hw_counters.c +++ b/drivers/infiniband/hw/bnxt_re/hw_counters.c @@ -82,6 +82,8 @@ static const struct rdma_stat_desc bnxt_re_stat_descs[] = { [BNXT_RE_TX_PKTS].name = "tx_pkts", [BNXT_RE_TX_BYTES].name = "tx_bytes", [BNXT_RE_RECOVERABLE_ERRORS].name = "recoverable_errors", + [BNXT_RE_TX_ERRORS].name = "tx_roce_errors", + [BNXT_RE_TX_DISCARDS].name = "tx_roce_discards", [BNXT_RE_RX_ERRORS].name = "rx_roce_errors", [BNXT_RE_RX_DISCARDS].name = "rx_roce_discards", [BNXT_RE_TO_RETRANSMITS].name = "to_retransmits", @@ -129,14 +131,21 @@ static const struct rdma_stat_desc bnxt_re_stat_descs[] = { [BNXT_RE_TX_READ_RES].name = "tx_read_resp", [BNXT_RE_TX_WRITE_REQ].name = "tx_write_req", [BNXT_RE_TX_SEND_REQ].name = "tx_send_req", + [BNXT_RE_TX_ROCE_PKTS].name = "tx_roce_only_pkts", + [BNXT_RE_TX_ROCE_BYTES].name = "tx_roce_only_bytes", [BNXT_RE_RX_ATOMIC_REQ].name = "rx_atomic_req", [BNXT_RE_RX_READ_REQ].name = "rx_read_req", [BNXT_RE_RX_READ_RESP].name = "rx_read_resp", [BNXT_RE_RX_WRITE_REQ].name = "rx_write_req", [BNXT_RE_RX_SEND_REQ].name = "rx_send_req", + [BNXT_RE_RX_ROCE_PKTS].name = "rx_roce_only_pkts", + [BNXT_RE_RX_ROCE_BYTES].name = "rx_roce_only_bytes", [BNXT_RE_RX_ROCE_GOOD_PKTS].name = "rx_roce_good_pkts", [BNXT_RE_RX_ROCE_GOOD_BYTES].name = "rx_roce_good_bytes", - [BNXT_RE_OOB].name = "rx_out_of_buffer" + [BNXT_RE_OOB].name = "rx_out_of_buffer", + [BNXT_RE_TX_CNP].name = "tx_cnp_pkts", + [BNXT_RE_RX_CNP].name = "rx_cnp_pkts", + [BNXT_RE_RX_ECN].name = "rx_ecn_marked_pkts", }; static void bnxt_re_copy_ext_stats(struct bnxt_re_dev *rdev, @@ -148,14 +157,22 @@ static void bnxt_re_copy_ext_stats(struct bnxt_re_dev *rdev, stats->value[BNXT_RE_TX_READ_RES] = s->tx_read_res; stats->value[BNXT_RE_TX_WRITE_REQ] = s->tx_write_req; stats->value[BNXT_RE_TX_SEND_REQ] = s->tx_send_req; + stats->value[BNXT_RE_TX_ROCE_PKTS] = s->tx_roce_pkts; + stats->value[BNXT_RE_TX_ROCE_BYTES] = s->tx_roce_bytes; stats->value[BNXT_RE_RX_ATOMIC_REQ] = s->rx_atomic_req; stats->value[BNXT_RE_RX_READ_REQ] = s->rx_read_req; stats->value[BNXT_RE_RX_READ_RESP] = s->rx_read_res; stats->value[BNXT_RE_RX_WRITE_REQ] = s->rx_write_req; stats->value[BNXT_RE_RX_SEND_REQ] = s->rx_send_req; + stats->value[BNXT_RE_RX_ROCE_PKTS] = s->rx_roce_pkts; + stats->value[BNXT_RE_RX_ROCE_BYTES] = s->rx_roce_bytes; stats->value[BNXT_RE_RX_ROCE_GOOD_PKTS] = s->rx_roce_good_pkts; stats->value[BNXT_RE_RX_ROCE_GOOD_BYTES] = s->rx_roce_good_bytes; stats->value[BNXT_RE_OOB] = s->rx_out_of_buffer; + stats->value[BNXT_RE_TX_CNP] = s->tx_cnp; + stats->value[BNXT_RE_RX_CNP] = s->rx_cnp; + stats->value[BNXT_RE_RX_ECN] = s->rx_ecn_marked; + stats->value[BNXT_RE_OUT_OF_SEQ_ERR] = s->rx_out_of_sequence; } static int bnxt_re_get_ext_stat(struct bnxt_re_dev *rdev, @@ -298,6 +315,10 @@ int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev, if (hw_stats) { stats->value[BNXT_RE_RECOVERABLE_ERRORS] = le64_to_cpu(hw_stats->tx_bcast_pkts); + stats->value[BNXT_RE_TX_DISCARDS] = + le64_to_cpu(hw_stats->tx_discard_pkts); + stats->value[BNXT_RE_TX_ERRORS] = + le64_to_cpu(hw_stats->tx_error_pkts); stats->value[BNXT_RE_RX_ERRORS] = le64_to_cpu(hw_stats->rx_error_pkts); stats->value[BNXT_RE_RX_DISCARDS] = @@ -319,6 +340,7 @@ int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev, &rdev->flags); goto done; } + bnxt_re_copy_err_stats(rdev, stats, err_s); if (_is_ext_stats_supported(rdev->dev_attr.dev_cap_flags) && !rdev->is_virtfn) { rc = bnxt_re_get_ext_stat(rdev, stats); @@ -328,7 +350,6 @@ int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev, goto done; } } - bnxt_re_copy_err_stats(rdev, stats, err_s); } done: diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.h b/drivers/infiniband/hw/bnxt_re/hw_counters.h index 7231a2b63620d..f3c4e35a23d87 100644 --- a/drivers/infiniband/hw/bnxt_re/hw_counters.h +++ b/drivers/infiniband/hw/bnxt_re/hw_counters.h @@ -65,6 +65,8 @@ enum bnxt_re_hw_stats { BNXT_RE_TX_PKTS, BNXT_RE_TX_BYTES, BNXT_RE_RECOVERABLE_ERRORS, + BNXT_RE_TX_ERRORS, + BNXT_RE_TX_DISCARDS, BNXT_RE_RX_ERRORS, BNXT_RE_RX_DISCARDS, BNXT_RE_TO_RETRANSMITS, @@ -112,14 +114,21 @@ enum bnxt_re_hw_stats { BNXT_RE_TX_READ_RES, BNXT_RE_TX_WRITE_REQ, BNXT_RE_TX_SEND_REQ, + BNXT_RE_TX_ROCE_PKTS, + BNXT_RE_TX_ROCE_BYTES, BNXT_RE_RX_ATOMIC_REQ, BNXT_RE_RX_READ_REQ, BNXT_RE_RX_READ_RESP, BNXT_RE_RX_WRITE_REQ, BNXT_RE_RX_SEND_REQ, + BNXT_RE_RX_ROCE_PKTS, + BNXT_RE_RX_ROCE_BYTES, BNXT_RE_RX_ROCE_GOOD_PKTS, BNXT_RE_RX_ROCE_GOOD_BYTES, BNXT_RE_OOB, + BNXT_RE_TX_CNP, + BNXT_RE_RX_CNP, + BNXT_RE_RX_ECN, BNXT_RE_NUM_EXT_COUNTERS }; diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c index ab45f9d4bb02f..7e57faab4f782 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c @@ -832,15 +832,22 @@ int bnxt_qplib_qext_stat(struct bnxt_qplib_rcfw *rcfw, u32 fid, estat->tx_read_res = le64_to_cpu(sb->tx_read_res_pkts); estat->tx_write_req = le64_to_cpu(sb->tx_write_req_pkts); estat->tx_send_req = le64_to_cpu(sb->tx_send_req_pkts); + estat->tx_roce_pkts = le64_to_cpu(sb->tx_roce_pkts); + estat->tx_roce_bytes = le64_to_cpu(sb->tx_roce_bytes); estat->rx_atomic_req = le64_to_cpu(sb->rx_atomic_req_pkts); estat->rx_read_req = le64_to_cpu(sb->rx_read_req_pkts); estat->rx_read_res = le64_to_cpu(sb->rx_read_res_pkts); estat->rx_write_req = le64_to_cpu(sb->rx_write_req_pkts); estat->rx_send_req = le64_to_cpu(sb->rx_send_req_pkts); + estat->rx_roce_pkts = le64_to_cpu(sb->rx_roce_pkts); + estat->rx_roce_bytes = le64_to_cpu(sb->rx_roce_bytes); estat->rx_roce_good_pkts = le64_to_cpu(sb->rx_roce_good_pkts); estat->rx_roce_good_bytes = le64_to_cpu(sb->rx_roce_good_bytes); estat->rx_out_of_buffer = le64_to_cpu(sb->rx_out_of_buffer_pkts); estat->rx_out_of_sequence = le64_to_cpu(sb->rx_out_of_sequence_pkts); + estat->tx_cnp = le64_to_cpu(sb->tx_cnp_pkts); + estat->rx_cnp = le64_to_cpu(sb->rx_cnp_pkts); + estat->rx_ecn_marked = le64_to_cpu(sb->rx_ecn_marked_pkts); bail: bnxt_qplib_rcfw_free_sbuf(rcfw, sbuf); -- GitLab From 8b6573ff3420a2da1deb469a480dbc454745f784 Mon Sep 17 00:00:00 2001 From: Chandramohan Akula Date: Wed, 26 Jul 2023 07:51:21 -0700 Subject: [PATCH 0580/3445] bnxt_re: Update the debug counters for doorbell pacing Add debug counters to track the Doorbell pacing events and report the doorbell pacing debug stats. Signed-off-by: Chandramohan Akula Signed-off-by: Selvin Xavier Link: https://lore.kernel.org/r/1690383081-15033-5-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/hw_counters.c | 18 ++++++++++++++++++ drivers/infiniband/hw/bnxt_re/hw_counters.h | 11 +++++++++++ drivers/infiniband/hw/bnxt_re/main.c | 3 +++ 3 files changed, 32 insertions(+) diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.c b/drivers/infiniband/hw/bnxt_re/hw_counters.c index e50a1cb1984b4..93572405d6fae 100644 --- a/drivers/infiniband/hw/bnxt_re/hw_counters.c +++ b/drivers/infiniband/hw/bnxt_re/hw_counters.c @@ -146,6 +146,10 @@ static const struct rdma_stat_desc bnxt_re_stat_descs[] = { [BNXT_RE_TX_CNP].name = "tx_cnp_pkts", [BNXT_RE_RX_CNP].name = "rx_cnp_pkts", [BNXT_RE_RX_ECN].name = "rx_ecn_marked_pkts", + [BNXT_RE_PACING_RESCHED].name = "pacing_reschedule", + [BNXT_RE_PACING_CMPL].name = "pacing_complete", + [BNXT_RE_PACING_ALERT].name = "pacing_alerts", + [BNXT_RE_DB_FIFO_REG].name = "db_fifo_register", }; static void bnxt_re_copy_ext_stats(struct bnxt_re_dev *rdev, @@ -278,6 +282,18 @@ static void bnxt_re_copy_err_stats(struct bnxt_re_dev *rdev, err_s->res_oos_drop_count; } +static void bnxt_re_copy_db_pacing_stats(struct bnxt_re_dev *rdev, + struct rdma_hw_stats *stats) +{ + struct bnxt_re_db_pacing_stats *pacing_s = &rdev->stats.pacing; + + stats->value[BNXT_RE_PACING_RESCHED] = pacing_s->resched; + stats->value[BNXT_RE_PACING_CMPL] = pacing_s->complete; + stats->value[BNXT_RE_PACING_ALERT] = pacing_s->alerts; + stats->value[BNXT_RE_DB_FIFO_REG] = + readl(rdev->en_dev->bar0 + rdev->pacing.dbr_db_fifo_reg_off); +} + int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev, struct rdma_hw_stats *stats, u32 port, int index) @@ -350,6 +366,8 @@ int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev, goto done; } } + if (rdev->pacing.dbr_pacing) + bnxt_re_copy_db_pacing_stats(rdev, stats); } done: diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.h b/drivers/infiniband/hw/bnxt_re/hw_counters.h index f3c4e35a23d87..e541b6f8ca9fe 100644 --- a/drivers/infiniband/hw/bnxt_re/hw_counters.h +++ b/drivers/infiniband/hw/bnxt_re/hw_counters.h @@ -129,11 +129,21 @@ enum bnxt_re_hw_stats { BNXT_RE_TX_CNP, BNXT_RE_RX_CNP, BNXT_RE_RX_ECN, + BNXT_RE_PACING_RESCHED, + BNXT_RE_PACING_CMPL, + BNXT_RE_PACING_ALERT, + BNXT_RE_DB_FIFO_REG, BNXT_RE_NUM_EXT_COUNTERS }; #define BNXT_RE_NUM_STD_COUNTERS (BNXT_RE_OUT_OF_SEQ_ERR + 1) +struct bnxt_re_db_pacing_stats { + u64 resched; + u64 complete; + u64 alerts; +}; + struct bnxt_re_res_cntrs { atomic_t qp_count; atomic_t rc_qp_count; @@ -164,6 +174,7 @@ struct bnxt_re_rstat { struct bnxt_re_stats { struct bnxt_re_rstat rstat; struct bnxt_re_res_cntrs res; + struct bnxt_re_db_pacing_stats pacing; }; struct rdma_hw_stats *bnxt_re_ib_alloc_hw_port_stats(struct ib_device *ibdev, diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index 91efa0400c594..87960ac420842 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -533,6 +533,7 @@ static void bnxt_re_db_fifo_check(struct work_struct *work) pacing_data->pacing_th * BNXT_RE_PACING_ALARM_TH_MULTIPLE; schedule_delayed_work(&rdev->dbq_pacing_work, msecs_to_jiffies(rdev->pacing.dbq_pacing_time)); + rdev->stats.pacing.alerts++; mutex_unlock(&rdev->pacing.dbq_lock); } @@ -563,12 +564,14 @@ static void bnxt_re_pacing_timer_exp(struct work_struct *work) pacing_data->do_pacing = max_t(u32, rdev->pacing.dbr_def_do_pacing, pacing_data->do_pacing); if (pacing_data->do_pacing <= rdev->pacing.dbr_def_do_pacing) { bnxt_re_set_default_pacing_data(rdev); + rdev->stats.pacing.complete++; goto dbq_unlock; } restart_timer: schedule_delayed_work(&rdev->dbq_pacing_work, msecs_to_jiffies(rdev->pacing.dbq_pacing_time)); + rdev->stats.pacing.resched++; dbq_unlock: rdev->pacing.do_pacing_save = pacing_data->do_pacing; mutex_unlock(&rdev->pacing.dbq_lock); -- GitLab From cb06b6b3f6cbc56c534587db2aac3e0958a4a314 Mon Sep 17 00:00:00 2001 From: Haoyue Xu Date: Fri, 21 Jul 2023 17:20:52 +0800 Subject: [PATCH 0581/3445] RDMA/core: Get IB width and speed from netdev Previously, there was no way to query the number of lanes for a network card, so the same netdev_speed would result in a fixed pair of width and speed. As network card specifications become more diverse, such fixed mode is no longer suitable, so a method is needed to obtain the correct width and speed based on the number of lanes. This patch retrieves netdev lanes and speed from net_device and translates them to IB width and speed. Signed-off-by: Haoyue Xu Signed-off-by: Luoyouming Signed-off-by: Junxian Huang Link: https://lore.kernel.org/r/20230721092052.2090449-1-huangjunxian6@hisilicon.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/core/verbs.c | 100 +++++++++++++++++++++++++------- 1 file changed, 79 insertions(+), 21 deletions(-) diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index b99b3cc283b65..25367bd6dd974 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -1880,6 +1880,80 @@ int ib_modify_qp_with_udata(struct ib_qp *ib_qp, struct ib_qp_attr *attr, } EXPORT_SYMBOL(ib_modify_qp_with_udata); +static void ib_get_width_and_speed(u32 netdev_speed, u32 lanes, + u16 *speed, u8 *width) +{ + if (!lanes) { + if (netdev_speed <= SPEED_1000) { + *width = IB_WIDTH_1X; + *speed = IB_SPEED_SDR; + } else if (netdev_speed <= SPEED_10000) { + *width = IB_WIDTH_1X; + *speed = IB_SPEED_FDR10; + } else if (netdev_speed <= SPEED_20000) { + *width = IB_WIDTH_4X; + *speed = IB_SPEED_DDR; + } else if (netdev_speed <= SPEED_25000) { + *width = IB_WIDTH_1X; + *speed = IB_SPEED_EDR; + } else if (netdev_speed <= SPEED_40000) { + *width = IB_WIDTH_4X; + *speed = IB_SPEED_FDR10; + } else { + *width = IB_WIDTH_4X; + *speed = IB_SPEED_EDR; + } + + return; + } + + switch (lanes) { + case 1: + *width = IB_WIDTH_1X; + break; + case 2: + *width = IB_WIDTH_2X; + break; + case 4: + *width = IB_WIDTH_4X; + break; + case 8: + *width = IB_WIDTH_8X; + break; + case 12: + *width = IB_WIDTH_12X; + break; + default: + *width = IB_WIDTH_1X; + } + + switch (netdev_speed / lanes) { + case SPEED_2500: + *speed = IB_SPEED_SDR; + break; + case SPEED_5000: + *speed = IB_SPEED_DDR; + break; + case SPEED_10000: + *speed = IB_SPEED_FDR10; + break; + case SPEED_14000: + *speed = IB_SPEED_FDR; + break; + case SPEED_25000: + *speed = IB_SPEED_EDR; + break; + case SPEED_50000: + *speed = IB_SPEED_HDR; + break; + case SPEED_100000: + *speed = IB_SPEED_NDR; + break; + default: + *speed = IB_SPEED_SDR; + } +} + int ib_get_eth_speed(struct ib_device *dev, u32 port_num, u16 *speed, u8 *width) { int rc; @@ -1904,29 +1978,13 @@ int ib_get_eth_speed(struct ib_device *dev, u32 port_num, u16 *speed, u8 *width) netdev_speed = lksettings.base.speed; } else { netdev_speed = SPEED_1000; - pr_warn("%s speed is unknown, defaulting to %u\n", netdev->name, - netdev_speed); + if (rc) + pr_warn("%s speed is unknown, defaulting to %u\n", + netdev->name, netdev_speed); } - if (netdev_speed <= SPEED_1000) { - *width = IB_WIDTH_1X; - *speed = IB_SPEED_SDR; - } else if (netdev_speed <= SPEED_10000) { - *width = IB_WIDTH_1X; - *speed = IB_SPEED_FDR10; - } else if (netdev_speed <= SPEED_20000) { - *width = IB_WIDTH_4X; - *speed = IB_SPEED_DDR; - } else if (netdev_speed <= SPEED_25000) { - *width = IB_WIDTH_1X; - *speed = IB_SPEED_EDR; - } else if (netdev_speed <= SPEED_40000) { - *width = IB_WIDTH_4X; - *speed = IB_SPEED_FDR10; - } else { - *width = IB_WIDTH_4X; - *speed = IB_SPEED_EDR; - } + ib_get_width_and_speed(netdev_speed, lksettings.lanes, + speed, width); return 0; } -- GitLab From 3a8498720450174b8db450d3375a04dca81b3534 Mon Sep 17 00:00:00 2001 From: Sindhu Devale Date: Tue, 25 Jul 2023 10:55:24 -0500 Subject: [PATCH 0582/3445] RDMA/irdma: Allow accurate reporting on QP max send/recv WR Currently the attribute cap.max_send_wr and cap.max_recv_wr sent from user-space during create QP are the provider computed SQ/RQ depth as opposed to raw values passed from application. This inhibits computation of an accurate value for max_send_wr and max_recv_wr for this QP in the kernel which matches the value returned in user create QP. Also these capabilities needs to be reported from the driver in query QP. Add support by extending the ABI to allow the raw cap.max_send_wr and cap.max_recv_wr to be passed from user-space, while keeping compatibility for the older scheme. The internal HW depth and shift needed for the WQs needs to be computed now for both kernel and user-mode QPs. Add new helpers to assist with this: irdma_uk_calc_depth_shift_sq, irdma_uk_calc_depth_shift_rq and irdma_uk_calc_depth_shift_wq. Consolidate all the user mode QP setup into a new function irdma_setup_umode_qp which keeps it with its counterpart irdma_setup_kmode_qp. Signed-off-by: Youvaraj Sagar Signed-off-by: Sindhu Devale Signed-off-by: Shiraz Saleem Link: https://lore.kernel.org/r/20230725155525.1081-2-shiraz.saleem@intel.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/irdma/uk.c | 89 +++++++++++--- drivers/infiniband/hw/irdma/user.h | 10 ++ drivers/infiniband/hw/irdma/verbs.c | 182 +++++++++++++++++----------- drivers/infiniband/hw/irdma/verbs.h | 3 +- include/uapi/rdma/irdma-abi.h | 6 + 5 files changed, 203 insertions(+), 87 deletions(-) diff --git a/drivers/infiniband/hw/irdma/uk.c b/drivers/infiniband/hw/irdma/uk.c index dd428d915c175..fd337caa2e3b7 100644 --- a/drivers/infiniband/hw/irdma/uk.c +++ b/drivers/infiniband/hw/irdma/uk.c @@ -1414,6 +1414,78 @@ static void irdma_setup_connection_wqes(struct irdma_qp_uk *qp, IRDMA_RING_MOVE_HEAD_BY_COUNT_NOCHECK(qp->initial_ring, move_cnt); } +/** + * irdma_uk_calc_shift_wq - calculate WQE shift for both SQ and RQ + * @ukinfo: qp initialization info + * @sq_shift: Returns shift of SQ + * @rq_shift: Returns shift of RQ + */ +void irdma_uk_calc_shift_wq(struct irdma_qp_uk_init_info *ukinfo, u8 *sq_shift, + u8 *rq_shift) +{ + bool imm_support = ukinfo->uk_attrs->hw_rev >= IRDMA_GEN_2; + + irdma_get_wqe_shift(ukinfo->uk_attrs, + imm_support ? ukinfo->max_sq_frag_cnt + 1 : + ukinfo->max_sq_frag_cnt, + ukinfo->max_inline_data, sq_shift); + + irdma_get_wqe_shift(ukinfo->uk_attrs, ukinfo->max_rq_frag_cnt, 0, + rq_shift); + + if (ukinfo->uk_attrs->hw_rev == IRDMA_GEN_1) { + if (ukinfo->abi_ver > 4) + *rq_shift = IRDMA_MAX_RQ_WQE_SHIFT_GEN1; + } +} + +/** + * irdma_uk_calc_depth_shift_sq - calculate depth and shift for SQ size. + * @ukinfo: qp initialization info + * @sq_depth: Returns depth of SQ + * @sq_shift: Returns shift of SQ + */ +int irdma_uk_calc_depth_shift_sq(struct irdma_qp_uk_init_info *ukinfo, + u32 *sq_depth, u8 *sq_shift) +{ + bool imm_support = ukinfo->uk_attrs->hw_rev >= IRDMA_GEN_2; + int status; + + irdma_get_wqe_shift(ukinfo->uk_attrs, + imm_support ? ukinfo->max_sq_frag_cnt + 1 : + ukinfo->max_sq_frag_cnt, + ukinfo->max_inline_data, sq_shift); + status = irdma_get_sqdepth(ukinfo->uk_attrs, ukinfo->sq_size, + *sq_shift, sq_depth); + + return status; +} + +/** + * irdma_uk_calc_depth_shift_rq - calculate depth and shift for RQ size. + * @ukinfo: qp initialization info + * @rq_depth: Returns depth of RQ + * @rq_shift: Returns shift of RQ + */ +int irdma_uk_calc_depth_shift_rq(struct irdma_qp_uk_init_info *ukinfo, + u32 *rq_depth, u8 *rq_shift) +{ + int status; + + irdma_get_wqe_shift(ukinfo->uk_attrs, ukinfo->max_rq_frag_cnt, 0, + rq_shift); + + if (ukinfo->uk_attrs->hw_rev == IRDMA_GEN_1) { + if (ukinfo->abi_ver > 4) + *rq_shift = IRDMA_MAX_RQ_WQE_SHIFT_GEN1; + } + + status = irdma_get_rqdepth(ukinfo->uk_attrs, ukinfo->rq_size, + *rq_shift, rq_depth); + + return status; +} + /** * irdma_uk_qp_init - initialize shared qp * @qp: hw qp (user and kernel) @@ -1428,23 +1500,12 @@ int irdma_uk_qp_init(struct irdma_qp_uk *qp, struct irdma_qp_uk_init_info *info) { int ret_code = 0; u32 sq_ring_size; - u8 sqshift, rqshift; qp->uk_attrs = info->uk_attrs; if (info->max_sq_frag_cnt > qp->uk_attrs->max_hw_wq_frags || info->max_rq_frag_cnt > qp->uk_attrs->max_hw_wq_frags) return -EINVAL; - irdma_get_wqe_shift(qp->uk_attrs, info->max_rq_frag_cnt, 0, &rqshift); - if (qp->uk_attrs->hw_rev == IRDMA_GEN_1) { - irdma_get_wqe_shift(qp->uk_attrs, info->max_sq_frag_cnt, - info->max_inline_data, &sqshift); - if (info->abi_ver > 4) - rqshift = IRDMA_MAX_RQ_WQE_SHIFT_GEN1; - } else { - irdma_get_wqe_shift(qp->uk_attrs, info->max_sq_frag_cnt + 1, - info->max_inline_data, &sqshift); - } qp->qp_caps = info->qp_caps; qp->sq_base = info->sq; qp->rq_base = info->rq; @@ -1458,7 +1519,7 @@ int irdma_uk_qp_init(struct irdma_qp_uk *qp, struct irdma_qp_uk_init_info *info) qp->sq_size = info->sq_size; qp->push_mode = false; qp->max_sq_frag_cnt = info->max_sq_frag_cnt; - sq_ring_size = qp->sq_size << sqshift; + sq_ring_size = qp->sq_size << info->sq_shift; IRDMA_RING_INIT(qp->sq_ring, sq_ring_size); IRDMA_RING_INIT(qp->initial_ring, sq_ring_size); if (info->first_sq_wq) { @@ -1473,9 +1534,9 @@ int irdma_uk_qp_init(struct irdma_qp_uk *qp, struct irdma_qp_uk_init_info *info) qp->rq_size = info->rq_size; qp->max_rq_frag_cnt = info->max_rq_frag_cnt; qp->max_inline_data = info->max_inline_data; - qp->rq_wqe_size = rqshift; + qp->rq_wqe_size = info->rq_shift; IRDMA_RING_INIT(qp->rq_ring, qp->rq_size); - qp->rq_wqe_size_multiplier = 1 << rqshift; + qp->rq_wqe_size_multiplier = 1 << info->rq_shift; if (qp->uk_attrs->hw_rev == IRDMA_GEN_1) qp->wqe_ops = iw_wqe_uk_ops_gen_1; else diff --git a/drivers/infiniband/hw/irdma/user.h b/drivers/infiniband/hw/irdma/user.h index d0cdf609f5e06..1e0e1a71dbada 100644 --- a/drivers/infiniband/hw/irdma/user.h +++ b/drivers/infiniband/hw/irdma/user.h @@ -295,6 +295,12 @@ void irdma_uk_cq_init(struct irdma_cq_uk *cq, struct irdma_cq_uk_init_info *info); int irdma_uk_qp_init(struct irdma_qp_uk *qp, struct irdma_qp_uk_init_info *info); +void irdma_uk_calc_shift_wq(struct irdma_qp_uk_init_info *ukinfo, u8 *sq_shift, + u8 *rq_shift); +int irdma_uk_calc_depth_shift_sq(struct irdma_qp_uk_init_info *ukinfo, + u32 *sq_depth, u8 *sq_shift); +int irdma_uk_calc_depth_shift_rq(struct irdma_qp_uk_init_info *ukinfo, + u32 *rq_depth, u8 *rq_shift); struct irdma_sq_uk_wr_trk_info { u64 wrid; u32 wr_len; @@ -374,8 +380,12 @@ struct irdma_qp_uk_init_info { u32 max_sq_frag_cnt; u32 max_rq_frag_cnt; u32 max_inline_data; + u32 sq_depth; + u32 rq_depth; u8 first_sq_wq; u8 type; + u8 sq_shift; + u8 rq_shift; int abi_ver; bool legacy_mode; }; diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c index a1a42a7cd7832..0187cff7b9c6f 100644 --- a/drivers/infiniband/hw/irdma/verbs.c +++ b/drivers/infiniband/hw/irdma/verbs.c @@ -277,7 +277,7 @@ static int irdma_alloc_ucontext(struct ib_ucontext *uctx, struct irdma_alloc_ucontext_req req = {}; struct irdma_alloc_ucontext_resp uresp = {}; struct irdma_ucontext *ucontext = to_ucontext(uctx); - struct irdma_uk_attrs *uk_attrs; + struct irdma_uk_attrs *uk_attrs = &iwdev->rf->sc_dev.hw_attrs.uk_attrs; if (udata->inlen < IRDMA_ALLOC_UCTX_MIN_REQ_LEN || udata->outlen < IRDMA_ALLOC_UCTX_MIN_RESP_LEN) @@ -292,7 +292,9 @@ static int irdma_alloc_ucontext(struct ib_ucontext *uctx, ucontext->iwdev = iwdev; ucontext->abi_ver = req.userspace_ver; - uk_attrs = &iwdev->rf->sc_dev.hw_attrs.uk_attrs; + if (req.comp_mask & IRDMA_ALLOC_UCTX_USE_RAW_ATTR) + ucontext->use_raw_attrs = true; + /* GEN_1 legacy support with libi40iw */ if (udata->outlen == IRDMA_ALLOC_UCTX_MIN_RESP_LEN) { if (uk_attrs->hw_rev != IRDMA_GEN_1) @@ -327,6 +329,7 @@ static int irdma_alloc_ucontext(struct ib_ucontext *uctx, uresp.max_hw_cq_size = uk_attrs->max_hw_cq_size; uresp.min_hw_cq_size = uk_attrs->min_hw_cq_size; uresp.hw_rev = uk_attrs->hw_rev; + uresp.comp_mask |= IRDMA_ALLOC_UCTX_USE_RAW_ATTR; if (ib_copy_to_udata(udata, &uresp, min(sizeof(uresp), udata->outlen))) { rdma_user_mmap_entry_remove(ucontext->db_mmap_entry); @@ -566,6 +569,86 @@ static void irdma_setup_virt_qp(struct irdma_device *iwdev, } } +/** + * irdma_setup_umode_qp - setup sq and rq size in user mode qp + * @iwdev: iwarp device + * @iwqp: qp ptr (user or kernel) + * @info: initialize info to return + * @init_attr: Initial QP create attributes + */ +static int irdma_setup_umode_qp(struct ib_udata *udata, + struct irdma_device *iwdev, + struct irdma_qp *iwqp, + struct irdma_qp_init_info *info, + struct ib_qp_init_attr *init_attr) +{ + struct irdma_ucontext *ucontext = rdma_udata_to_drv_context(udata, + struct irdma_ucontext, ibucontext); + struct irdma_qp_uk_init_info *ukinfo = &info->qp_uk_init_info; + struct irdma_create_qp_req req; + unsigned long flags; + int ret; + + ret = ib_copy_from_udata(&req, udata, + min(sizeof(req), udata->inlen)); + if (ret) { + ibdev_dbg(&iwdev->ibdev, "VERBS: ib_copy_from_data fail\n"); + return ret; + } + + iwqp->ctx_info.qp_compl_ctx = req.user_compl_ctx; + iwqp->user_mode = 1; + if (req.user_wqe_bufs) { + info->qp_uk_init_info.legacy_mode = ucontext->legacy_mode; + spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags); + iwqp->iwpbl = irdma_get_pbl((unsigned long)req.user_wqe_bufs, + &ucontext->qp_reg_mem_list); + spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags); + + if (!iwqp->iwpbl) { + ret = -ENODATA; + ibdev_dbg(&iwdev->ibdev, "VERBS: no pbl info\n"); + return ret; + } + } + + if (!ucontext->use_raw_attrs) { + /** + * Maintain backward compat with older ABI which passes sq and + * rq depth in quanta in cap.max_send_wr and cap.max_recv_wr. + * There is no way to compute the correct value of + * iwqp->max_send_wr/max_recv_wr in the kernel. + */ + iwqp->max_send_wr = init_attr->cap.max_send_wr; + iwqp->max_recv_wr = init_attr->cap.max_recv_wr; + ukinfo->sq_size = init_attr->cap.max_send_wr; + ukinfo->rq_size = init_attr->cap.max_recv_wr; + irdma_uk_calc_shift_wq(ukinfo, &ukinfo->sq_shift, + &ukinfo->rq_shift); + } else { + ret = irdma_uk_calc_depth_shift_sq(ukinfo, &ukinfo->sq_depth, + &ukinfo->sq_shift); + if (ret) + return ret; + + ret = irdma_uk_calc_depth_shift_rq(ukinfo, &ukinfo->rq_depth, + &ukinfo->rq_shift); + if (ret) + return ret; + + iwqp->max_send_wr = + (ukinfo->sq_depth - IRDMA_SQ_RSVD) >> ukinfo->sq_shift; + iwqp->max_recv_wr = + (ukinfo->rq_depth - IRDMA_RQ_RSVD) >> ukinfo->rq_shift; + ukinfo->sq_size = ukinfo->sq_depth >> ukinfo->sq_shift; + ukinfo->rq_size = ukinfo->rq_depth >> ukinfo->rq_shift; + } + + irdma_setup_virt_qp(iwdev, iwqp, info); + + return 0; +} + /** * irdma_setup_kmode_qp - setup initialization for kernel mode qp * @iwdev: iwarp device @@ -579,40 +662,28 @@ static int irdma_setup_kmode_qp(struct irdma_device *iwdev, struct ib_qp_init_attr *init_attr) { struct irdma_dma_mem *mem = &iwqp->kqp.dma_mem; - u32 sqdepth, rqdepth; - u8 sqshift, rqshift; u32 size; int status; struct irdma_qp_uk_init_info *ukinfo = &info->qp_uk_init_info; - struct irdma_uk_attrs *uk_attrs = &iwdev->rf->sc_dev.hw_attrs.uk_attrs; - irdma_get_wqe_shift(uk_attrs, - uk_attrs->hw_rev >= IRDMA_GEN_2 ? ukinfo->max_sq_frag_cnt + 1 : - ukinfo->max_sq_frag_cnt, - ukinfo->max_inline_data, &sqshift); - status = irdma_get_sqdepth(uk_attrs, ukinfo->sq_size, sqshift, - &sqdepth); + status = irdma_uk_calc_depth_shift_sq(ukinfo, &ukinfo->sq_depth, + &ukinfo->sq_shift); if (status) return status; - if (uk_attrs->hw_rev == IRDMA_GEN_1) - rqshift = IRDMA_MAX_RQ_WQE_SHIFT_GEN1; - else - irdma_get_wqe_shift(uk_attrs, ukinfo->max_rq_frag_cnt, 0, - &rqshift); - - status = irdma_get_rqdepth(uk_attrs, ukinfo->rq_size, rqshift, - &rqdepth); + status = irdma_uk_calc_depth_shift_rq(ukinfo, &ukinfo->rq_depth, + &ukinfo->rq_shift); if (status) return status; iwqp->kqp.sq_wrid_mem = - kcalloc(sqdepth, sizeof(*iwqp->kqp.sq_wrid_mem), GFP_KERNEL); + kcalloc(ukinfo->sq_depth, sizeof(*iwqp->kqp.sq_wrid_mem), GFP_KERNEL); if (!iwqp->kqp.sq_wrid_mem) return -ENOMEM; iwqp->kqp.rq_wrid_mem = - kcalloc(rqdepth, sizeof(*iwqp->kqp.rq_wrid_mem), GFP_KERNEL); + kcalloc(ukinfo->rq_depth, sizeof(*iwqp->kqp.rq_wrid_mem), GFP_KERNEL); + if (!iwqp->kqp.rq_wrid_mem) { kfree(iwqp->kqp.sq_wrid_mem); iwqp->kqp.sq_wrid_mem = NULL; @@ -622,7 +693,7 @@ static int irdma_setup_kmode_qp(struct irdma_device *iwdev, ukinfo->sq_wrtrk_array = iwqp->kqp.sq_wrid_mem; ukinfo->rq_wrid_array = iwqp->kqp.rq_wrid_mem; - size = (sqdepth + rqdepth) * IRDMA_QP_WQE_MIN_SIZE; + size = (ukinfo->sq_depth + ukinfo->rq_depth) * IRDMA_QP_WQE_MIN_SIZE; size += (IRDMA_SHADOW_AREA_SIZE << 3); mem->size = ALIGN(size, 256); @@ -638,16 +709,19 @@ static int irdma_setup_kmode_qp(struct irdma_device *iwdev, ukinfo->sq = mem->va; info->sq_pa = mem->pa; - ukinfo->rq = &ukinfo->sq[sqdepth]; - info->rq_pa = info->sq_pa + (sqdepth * IRDMA_QP_WQE_MIN_SIZE); - ukinfo->shadow_area = ukinfo->rq[rqdepth].elem; - info->shadow_area_pa = info->rq_pa + (rqdepth * IRDMA_QP_WQE_MIN_SIZE); - ukinfo->sq_size = sqdepth >> sqshift; - ukinfo->rq_size = rqdepth >> rqshift; + ukinfo->rq = &ukinfo->sq[ukinfo->sq_depth]; + info->rq_pa = info->sq_pa + (ukinfo->sq_depth * IRDMA_QP_WQE_MIN_SIZE); + ukinfo->shadow_area = ukinfo->rq[ukinfo->rq_depth].elem; + info->shadow_area_pa = + info->rq_pa + (ukinfo->rq_depth * IRDMA_QP_WQE_MIN_SIZE); + ukinfo->sq_size = ukinfo->sq_depth >> ukinfo->sq_shift; + ukinfo->rq_size = ukinfo->rq_depth >> ukinfo->rq_shift; ukinfo->qp_id = iwqp->ibqp.qp_num; - init_attr->cap.max_send_wr = (sqdepth - IRDMA_SQ_RSVD) >> sqshift; - init_attr->cap.max_recv_wr = (rqdepth - IRDMA_RQ_RSVD) >> rqshift; + iwqp->max_send_wr = (ukinfo->sq_depth - IRDMA_SQ_RSVD) >> ukinfo->sq_shift; + iwqp->max_recv_wr = (ukinfo->rq_depth - IRDMA_RQ_RSVD) >> ukinfo->rq_shift; + init_attr->cap.max_send_wr = iwqp->max_send_wr; + init_attr->cap.max_recv_wr = iwqp->max_recv_wr; return 0; } @@ -803,18 +877,14 @@ static int irdma_create_qp(struct ib_qp *ibqp, struct irdma_device *iwdev = to_iwdev(ibpd->device); struct irdma_pci_f *rf = iwdev->rf; struct irdma_qp *iwqp = to_iwqp(ibqp); - struct irdma_create_qp_req req = {}; struct irdma_create_qp_resp uresp = {}; u32 qp_num = 0; int err_code; - int sq_size; - int rq_size; struct irdma_sc_qp *qp; struct irdma_sc_dev *dev = &rf->sc_dev; struct irdma_uk_attrs *uk_attrs = &dev->hw_attrs.uk_attrs; struct irdma_qp_init_info init_info = {}; struct irdma_qp_host_ctx_info *ctx_info; - unsigned long flags; err_code = irdma_validate_qp_attrs(init_attr, iwdev); if (err_code) @@ -824,13 +894,10 @@ static int irdma_create_qp(struct ib_qp *ibqp, udata->outlen < IRDMA_CREATE_QP_MIN_RESP_LEN)) return -EINVAL; - sq_size = init_attr->cap.max_send_wr; - rq_size = init_attr->cap.max_recv_wr; - init_info.vsi = &iwdev->vsi; init_info.qp_uk_init_info.uk_attrs = uk_attrs; - init_info.qp_uk_init_info.sq_size = sq_size; - init_info.qp_uk_init_info.rq_size = rq_size; + init_info.qp_uk_init_info.sq_size = init_attr->cap.max_send_wr; + init_info.qp_uk_init_info.rq_size = init_attr->cap.max_recv_wr; init_info.qp_uk_init_info.max_sq_frag_cnt = init_attr->cap.max_send_sge; init_info.qp_uk_init_info.max_rq_frag_cnt = init_attr->cap.max_recv_sge; init_info.qp_uk_init_info.max_inline_data = init_attr->cap.max_inline_data; @@ -880,36 +947,9 @@ static int irdma_create_qp(struct ib_qp *ibqp, init_waitqueue_head(&iwqp->mod_qp_waitq); if (udata) { - err_code = ib_copy_from_udata(&req, udata, - min(sizeof(req), udata->inlen)); - if (err_code) { - ibdev_dbg(&iwdev->ibdev, - "VERBS: ib_copy_from_data fail\n"); - goto error; - } - - iwqp->ctx_info.qp_compl_ctx = req.user_compl_ctx; - iwqp->user_mode = 1; - if (req.user_wqe_bufs) { - struct irdma_ucontext *ucontext = - rdma_udata_to_drv_context(udata, - struct irdma_ucontext, - ibucontext); - - init_info.qp_uk_init_info.legacy_mode = ucontext->legacy_mode; - spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags); - iwqp->iwpbl = irdma_get_pbl((unsigned long)req.user_wqe_bufs, - &ucontext->qp_reg_mem_list); - spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags); - - if (!iwqp->iwpbl) { - err_code = -ENODATA; - ibdev_dbg(&iwdev->ibdev, "VERBS: no pbl info\n"); - goto error; - } - } init_info.qp_uk_init_info.abi_ver = iwpd->sc_pd.abi_ver; - irdma_setup_virt_qp(iwdev, iwqp, &init_info); + err_code = irdma_setup_umode_qp(udata, iwdev, iwqp, &init_info, + init_attr); } else { INIT_DELAYED_WORK(&iwqp->dwork_flush, irdma_flush_worker); init_info.qp_uk_init_info.abi_ver = IRDMA_ABI_VER; @@ -964,8 +1004,6 @@ static int irdma_create_qp(struct ib_qp *ibqp, spin_lock_init(&iwqp->sc_qp.pfpdu.lock); iwqp->sig_all = (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) ? 1 : 0; rf->qp_table[qp_num] = iwqp; - iwqp->max_send_wr = sq_size; - iwqp->max_recv_wr = rq_size; if (rdma_protocol_roce(&iwdev->ibdev, 1)) { if (dev->ws_add(&iwdev->vsi, 0)) { @@ -986,8 +1024,8 @@ static int irdma_create_qp(struct ib_qp *ibqp, if (rdma_protocol_iwarp(&iwdev->ibdev, 1)) uresp.lsmm = 1; } - uresp.actual_sq_size = sq_size; - uresp.actual_rq_size = rq_size; + uresp.actual_sq_size = init_info.qp_uk_init_info.sq_size; + uresp.actual_rq_size = init_info.qp_uk_init_info.rq_size; uresp.qp_id = qp_num; uresp.qp_caps = qp->qp_uk.qp_caps; diff --git a/drivers/infiniband/hw/irdma/verbs.h b/drivers/infiniband/hw/irdma/verbs.h index 9de7217df357d..5d7b983f47a24 100644 --- a/drivers/infiniband/hw/irdma/verbs.h +++ b/drivers/infiniband/hw/irdma/verbs.h @@ -18,7 +18,8 @@ struct irdma_ucontext { struct list_head qp_reg_mem_list; spinlock_t qp_reg_mem_list_lock; /* protect QP memory list */ int abi_ver; - bool legacy_mode; + u8 legacy_mode : 1; + u8 use_raw_attrs : 1; }; struct irdma_pd { diff --git a/include/uapi/rdma/irdma-abi.h b/include/uapi/rdma/irdma-abi.h index a7085e092d348..3a0cde4dcf331 100644 --- a/include/uapi/rdma/irdma-abi.h +++ b/include/uapi/rdma/irdma-abi.h @@ -22,10 +22,15 @@ enum irdma_memreg_type { IRDMA_MEMREG_TYPE_CQ = 2, }; +enum { + IRDMA_ALLOC_UCTX_USE_RAW_ATTR = 1 << 0, +}; + struct irdma_alloc_ucontext_req { __u32 rsvd32; __u8 userspace_ver; __u8 rsvd8[3]; + __aligned_u64 comp_mask; }; struct irdma_alloc_ucontext_resp { @@ -46,6 +51,7 @@ struct irdma_alloc_ucontext_resp { __u16 max_hw_sq_chunk; __u8 hw_rev; __u8 rsvd2; + __aligned_u64 comp_mask; }; struct irdma_alloc_pd_resp { -- GitLab From 72d422c2465e93d5de622173f04d666cb9854c5f Mon Sep 17 00:00:00 2001 From: Sindhu Devale Date: Tue, 25 Jul 2023 10:55:25 -0500 Subject: [PATCH 0583/3445] RDMA/irdma: Use HW specific minimum WQ size HW GEN1 and GEN2 have different min WQ sizes but they are currently set to the same value. Use a gen specific attribute min_hw_wq_size and extend ABI to pass it to user-space. Signed-off-by: Sindhu Devale Signed-off-by: Shiraz Saleem Link: https://lore.kernel.org/r/20230725155525.1081-3-shiraz.saleem@intel.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/irdma/i40iw_hw.c | 1 + drivers/infiniband/hw/irdma/i40iw_hw.h | 2 +- drivers/infiniband/hw/irdma/icrdma_hw.c | 1 + drivers/infiniband/hw/irdma/icrdma_hw.h | 1 + drivers/infiniband/hw/irdma/irdma.h | 1 + drivers/infiniband/hw/irdma/uk.c | 12 ++++++++---- drivers/infiniband/hw/irdma/user.h | 1 + drivers/infiniband/hw/irdma/verbs.c | 2 ++ include/uapi/rdma/irdma-abi.h | 3 +++ 9 files changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/hw/irdma/i40iw_hw.c b/drivers/infiniband/hw/irdma/i40iw_hw.c index 37a40fb4d0d7e..638d127fb3e0e 100644 --- a/drivers/infiniband/hw/irdma/i40iw_hw.c +++ b/drivers/infiniband/hw/irdma/i40iw_hw.c @@ -254,5 +254,6 @@ void i40iw_init_hw(struct irdma_sc_dev *dev) dev->hw_attrs.max_stat_idx = IRDMA_HW_STAT_INDEX_MAX_GEN_1; dev->hw_attrs.max_hw_outbound_msg_size = I40IW_MAX_OUTBOUND_MSG_SIZE; dev->hw_attrs.max_hw_inbound_msg_size = I40IW_MAX_INBOUND_MSG_SIZE; + dev->hw_attrs.uk_attrs.min_hw_wq_size = I40IW_MIN_WQ_SIZE; dev->hw_attrs.max_qp_wr = I40IW_MAX_QP_WRS; } diff --git a/drivers/infiniband/hw/irdma/i40iw_hw.h b/drivers/infiniband/hw/irdma/i40iw_hw.h index 1c438b3593ea8..10afc165f5ea9 100644 --- a/drivers/infiniband/hw/irdma/i40iw_hw.h +++ b/drivers/infiniband/hw/irdma/i40iw_hw.h @@ -140,11 +140,11 @@ enum i40iw_device_caps_const { I40IW_MAX_CQ_SIZE = 1048575, I40IW_MAX_OUTBOUND_MSG_SIZE = 2147483647, I40IW_MAX_INBOUND_MSG_SIZE = 2147483647, + I40IW_MIN_WQ_SIZE = 4 /* WQEs */, }; #define I40IW_QP_WQE_MIN_SIZE 32 #define I40IW_QP_WQE_MAX_SIZE 128 -#define I40IW_QP_SW_MIN_WQSIZE 4 #define I40IW_MAX_RQ_WQE_SHIFT 2 #define I40IW_MAX_QUANTA_PER_WR 2 diff --git a/drivers/infiniband/hw/irdma/icrdma_hw.c b/drivers/infiniband/hw/irdma/icrdma_hw.c index 298d14905993b..10ccf4bc3f2d2 100644 --- a/drivers/infiniband/hw/irdma/icrdma_hw.c +++ b/drivers/infiniband/hw/irdma/icrdma_hw.c @@ -195,6 +195,7 @@ void icrdma_init_hw(struct irdma_sc_dev *dev) dev->hw_attrs.max_stat_inst = ICRDMA_MAX_STATS_COUNT; dev->hw_attrs.max_stat_idx = IRDMA_HW_STAT_INDEX_MAX_GEN_2; + dev->hw_attrs.uk_attrs.min_hw_wq_size = ICRDMA_MIN_WQ_SIZE; dev->hw_attrs.uk_attrs.max_hw_sq_chunk = IRDMA_MAX_QUANTA_PER_WR; dev->hw_attrs.uk_attrs.feature_flags |= IRDMA_FEATURE_RTS_AE | IRDMA_FEATURE_CQ_RESIZE; diff --git a/drivers/infiniband/hw/irdma/icrdma_hw.h b/drivers/infiniband/hw/irdma/icrdma_hw.h index b65c463abf0b3..54035a08cc93b 100644 --- a/drivers/infiniband/hw/irdma/icrdma_hw.h +++ b/drivers/infiniband/hw/irdma/icrdma_hw.h @@ -64,6 +64,7 @@ enum icrdma_device_caps_const { ICRDMA_MAX_IRD_SIZE = 127, ICRDMA_MAX_ORD_SIZE = 255, + ICRDMA_MIN_WQ_SIZE = 8 /* WQEs */, }; diff --git a/drivers/infiniband/hw/irdma/irdma.h b/drivers/infiniband/hw/irdma/irdma.h index 173e2dc2fc355..3237fa64bc8f9 100644 --- a/drivers/infiniband/hw/irdma/irdma.h +++ b/drivers/infiniband/hw/irdma/irdma.h @@ -119,6 +119,7 @@ struct irdma_uk_attrs { u32 min_hw_cq_size; u32 max_hw_cq_size; u16 max_hw_sq_chunk; + u16 min_hw_wq_size; u8 hw_rev; }; diff --git a/drivers/infiniband/hw/irdma/uk.c b/drivers/infiniband/hw/irdma/uk.c index fd337caa2e3b7..ac650a784245b 100644 --- a/drivers/infiniband/hw/irdma/uk.c +++ b/drivers/infiniband/hw/irdma/uk.c @@ -1349,10 +1349,12 @@ void irdma_get_wqe_shift(struct irdma_uk_attrs *uk_attrs, u32 sge, int irdma_get_sqdepth(struct irdma_uk_attrs *uk_attrs, u32 sq_size, u8 shift, u32 *sqdepth) { + u32 min_size = (u32)uk_attrs->min_hw_wq_size << shift; + *sqdepth = irdma_qp_round_up((sq_size << shift) + IRDMA_SQ_RSVD); - if (*sqdepth < (IRDMA_QP_SW_MIN_WQSIZE << shift)) - *sqdepth = IRDMA_QP_SW_MIN_WQSIZE << shift; + if (*sqdepth < min_size) + *sqdepth = min_size; else if (*sqdepth > uk_attrs->max_hw_wq_quanta) return -EINVAL; @@ -1369,10 +1371,12 @@ int irdma_get_sqdepth(struct irdma_uk_attrs *uk_attrs, u32 sq_size, u8 shift, int irdma_get_rqdepth(struct irdma_uk_attrs *uk_attrs, u32 rq_size, u8 shift, u32 *rqdepth) { + u32 min_size = (u32)uk_attrs->min_hw_wq_size << shift; + *rqdepth = irdma_qp_round_up((rq_size << shift) + IRDMA_RQ_RSVD); - if (*rqdepth < (IRDMA_QP_SW_MIN_WQSIZE << shift)) - *rqdepth = IRDMA_QP_SW_MIN_WQSIZE << shift; + if (*rqdepth < min_size) + *rqdepth = min_size; else if (*rqdepth > uk_attrs->max_hw_rq_quanta) return -EINVAL; diff --git a/drivers/infiniband/hw/irdma/user.h b/drivers/infiniband/hw/irdma/user.h index 1e0e1a71dbada..dd145ec72a915 100644 --- a/drivers/infiniband/hw/irdma/user.h +++ b/drivers/infiniband/hw/irdma/user.h @@ -85,6 +85,7 @@ enum irdma_device_caps_const { IRDMA_Q2_BUF_SIZE = 256, IRDMA_QP_CTX_SIZE = 256, IRDMA_MAX_PDS = 262144, + IRDMA_MIN_WQ_SIZE_GEN2 = 8, }; enum irdma_addressing_type { diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c index 0187cff7b9c6f..b9420b0c42b33 100644 --- a/drivers/infiniband/hw/irdma/verbs.c +++ b/drivers/infiniband/hw/irdma/verbs.c @@ -330,6 +330,8 @@ static int irdma_alloc_ucontext(struct ib_ucontext *uctx, uresp.min_hw_cq_size = uk_attrs->min_hw_cq_size; uresp.hw_rev = uk_attrs->hw_rev; uresp.comp_mask |= IRDMA_ALLOC_UCTX_USE_RAW_ATTR; + uresp.min_hw_wq_size = uk_attrs->min_hw_wq_size; + uresp.comp_mask |= IRDMA_ALLOC_UCTX_MIN_HW_WQ_SIZE; if (ib_copy_to_udata(udata, &uresp, min(sizeof(uresp), udata->outlen))) { rdma_user_mmap_entry_remove(ucontext->db_mmap_entry); diff --git a/include/uapi/rdma/irdma-abi.h b/include/uapi/rdma/irdma-abi.h index 3a0cde4dcf331..bb18f15489e37 100644 --- a/include/uapi/rdma/irdma-abi.h +++ b/include/uapi/rdma/irdma-abi.h @@ -24,6 +24,7 @@ enum irdma_memreg_type { enum { IRDMA_ALLOC_UCTX_USE_RAW_ATTR = 1 << 0, + IRDMA_ALLOC_UCTX_MIN_HW_WQ_SIZE = 1 << 1, }; struct irdma_alloc_ucontext_req { @@ -52,6 +53,8 @@ struct irdma_alloc_ucontext_resp { __u8 hw_rev; __u8 rsvd2; __aligned_u64 comp_mask; + __u16 min_hw_wq_size; + __u8 rsvd3[6]; }; struct irdma_alloc_pd_resp { -- GitLab From e7186af7fb2609584a8bfb3da3c6ae09da5a5224 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Google)" Date: Thu, 13 Jul 2023 09:26:05 -0400 Subject: [PATCH 0584/3445] tracing: Add back FORTIFY_SOURCE logic to kernel_stack event structure For backward compatibility, older tooling expects to see the kernel_stack event with a "caller" field that is a fixed size array of 8 addresses. The code now supports more than 8 with an added "size" field that states the real number of entries. But the "caller" field still just looks like a fixed size to user space. Since the tracing macros that create the user space format files also creates the structures that those files represent, the kernel_stack event structure had its "caller" field a fixed size of 8, but in reality, when it is allocated on the ring buffer, it can hold more if the stack trace is bigger that 8 functions. The copying of these entries was simply done with a memcpy(): size = nr_entries * sizeof(unsigned long); memcpy(entry->caller, fstack->calls, size); The FORTIFY_SOURCE logic noticed at runtime that when the nr_entries was larger than 8, that the memcpy() was writing more than what the structure stated it can hold and it complained about it. This is because the FORTIFY_SOURCE code is unaware that the amount allocated is actually enough to hold the size. It does not expect that a fixed size field will hold more than the fixed size. This was originally solved by hiding the caller assignment with some pointer arithmetic. ptr = ring_buffer_data(); entry = ptr; ptr += offsetof(typeof(*entry), caller); memcpy(ptr, fstack->calls, size); But it is considered bad form to hide from kernel hardening. Instead, make it work nicely with FORTIFY_SOURCE by adding a new __stack_array() macro that is specific for this one special use case. The macro will take 4 arguments: type, item, len, field (whereas the __array() macro takes just the first three). This macro will act just like the __array() macro when creating the code to deal with the format file that is exposed to user space. But for the kernel, it will turn the caller field into: type item[] __counted_by(field); or for this instance: unsigned long caller[] __counted_by(size); Now the kernel code can expose the assignment of the caller to the FORTIFY_SOURCE and everyone is happy! Link: https://lore.kernel.org/linux-trace-kernel/20230712105235.5fc441aa@gandalf.local.home/ Link: https://lore.kernel.org/linux-trace-kernel/20230713092605.2ddb9788@rorschach.local.home Cc: Masami Hiramatsu Cc: Mark Rutland Cc: Sven Schnelle Suggested-by: Kees Cook Signed-off-by: Steven Rostedt (Google) Reviewed-by: Kees Cook --- kernel/trace/trace.c | 25 ++++--------------------- kernel/trace/trace.h | 10 ++++++++++ kernel/trace/trace_entries.h | 2 +- kernel/trace/trace_export.c | 9 +++++++++ 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index b8870078ef58d..f6ed6b79d91f1 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -3119,7 +3119,6 @@ static void __ftrace_trace_stack(struct trace_buffer *buffer, struct ftrace_stack *fstack; struct stack_entry *entry; int stackidx; - void *ptr; /* * Add one, for this function and the call to save_stack_trace() @@ -3157,32 +3156,16 @@ static void __ftrace_trace_stack(struct trace_buffer *buffer, nr_entries = stack_trace_save(fstack->calls, size, skip); } - size = nr_entries * sizeof(unsigned long); event = __trace_buffer_lock_reserve(buffer, TRACE_STACK, - (sizeof(*entry) - sizeof(entry->caller)) + size, + struct_size(entry, caller, nr_entries), trace_ctx); if (!event) goto out; - ptr = ring_buffer_event_data(event); - entry = ptr; - - /* - * For backward compatibility reasons, the entry->caller is an - * array of 8 slots to store the stack. This is also exported - * to user space. The amount allocated on the ring buffer actually - * holds enough for the stack specified by nr_entries. This will - * go into the location of entry->caller. Due to string fortifiers - * checking the size of the destination of memcpy() it triggers - * when it detects that size is greater than 8. To hide this from - * the fortifiers, we use "ptr" and pointer arithmetic to assign caller. - * - * The below is really just: - * memcpy(&entry->caller, fstack->calls, size); - */ - ptr += offsetof(typeof(*entry), caller); - memcpy(ptr, fstack->calls, size); + entry = ring_buffer_event_data(event); entry->size = nr_entries; + memcpy(&entry->caller, fstack->calls, + flex_array_size(entry, caller, nr_entries)); if (!call_filter_check_discard(call, entry, buffer, event)) __buffer_unlock_commit(buffer, event); diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index e1edc2197fc89..ba7ababb8308b 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -77,6 +77,16 @@ enum trace_type { #undef __array #define __array(type, item, size) type item[size]; +/* + * For backward compatibility, older user space expects to see the + * kernel_stack event with a fixed size caller field. But today the fix + * size is ignored by the kernel, and the real structure is dynamic. + * Expose to user space: "unsigned long caller[8];" but the real structure + * will be "unsigned long caller[] __counted_by(size)" + */ +#undef __stack_array +#define __stack_array(type, item, size, field) type item[] __counted_by(field); + #undef __array_desc #define __array_desc(type, container, item, size) diff --git a/kernel/trace/trace_entries.h b/kernel/trace/trace_entries.h index 340b2fa98218a..c47422b209085 100644 --- a/kernel/trace/trace_entries.h +++ b/kernel/trace/trace_entries.h @@ -190,7 +190,7 @@ FTRACE_ENTRY(kernel_stack, stack_entry, F_STRUCT( __field( int, size ) - __array( unsigned long, caller, FTRACE_STACK_ENTRIES ) + __stack_array( unsigned long, caller, FTRACE_STACK_ENTRIES, size) ), F_printk("\t=> %ps\n\t=> %ps\n\t=> %ps\n" diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c index 58f3946081e21..1698fc22afa0a 100644 --- a/kernel/trace/trace_export.c +++ b/kernel/trace/trace_export.c @@ -51,6 +51,9 @@ static int ftrace_event_register(struct trace_event_call *call, #undef __array #define __array(type, item, size) type item[size]; +#undef __stack_array +#define __stack_array(type, item, size, field) __array(type, item, size) + #undef __array_desc #define __array_desc(type, container, item, size) type item[size]; @@ -114,6 +117,9 @@ static void __always_unused ____ftrace_check_##name(void) \ is_signed_type(_type), .filter_type = FILTER_OTHER, \ .len = _len }, +#undef __stack_array +#define __stack_array(_type, _item, _len, _field) __array(_type, _item, _len) + #undef __array_desc #define __array_desc(_type, _container, _item, _len) __array(_type, _item, _len) @@ -149,6 +155,9 @@ static struct trace_event_fields ftrace_event_fields_##name[] = { \ #undef __array #define __array(type, item, len) +#undef __stack_array +#define __stack_array(type, item, len, field) + #undef __array_desc #define __array_desc(type, container, item, len) -- GitLab From 00a8478f8f5c0201004240746dd74d69d86fc0c4 Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Fri, 14 Jul 2023 17:43:34 +0200 Subject: [PATCH 0585/3445] ring_buffer: Use try_cmpxchg instead of cmpxchg Use try_cmpxchg instead of cmpxchg (*ptr, old, new) == old in ring_buffer.c. x86 CMPXCHG instruction returns success in ZF flag, so this change saves a compare after cmpxchg (and related move instruction in front of cmpxchg). No functional change intended. Link: https://lore.kernel.org/linux-trace-kernel/20230714154418.8884-1-ubizjak@gmail.com Cc: Steven Rostedt Cc: Masami Hiramatsu Signed-off-by: Uros Bizjak Signed-off-by: Steven Rostedt (Google) --- kernel/trace/ring_buffer.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 52dea5dd5362e..78502d4c7214e 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -692,10 +692,7 @@ static void rb_time_set(rb_time_t *t, u64 val) static inline bool rb_time_read_cmpxchg(local_t *l, unsigned long expect, unsigned long set) { - unsigned long ret; - - ret = local_cmpxchg(l, expect, set); - return ret == expect; + return local_try_cmpxchg(l, &expect, set); } static bool rb_time_cmpxchg(rb_time_t *t, u64 expect, u64 set) @@ -752,9 +749,7 @@ static void rb_time_set(rb_time_t *t, u64 val) static bool rb_time_cmpxchg(rb_time_t *t, u64 expect, u64 set) { - u64 val; - val = local64_cmpxchg(&t->time, expect, set); - return val == expect; + return local64_try_cmpxchg(&t->time, &expect, set); } #endif @@ -1494,14 +1489,11 @@ static bool rb_head_page_replace(struct buffer_page *old, { unsigned long *ptr = (unsigned long *)&old->list.prev->next; unsigned long val; - unsigned long ret; val = *ptr & ~RB_FLAG_MASK; val |= RB_PAGE_HEAD; - ret = cmpxchg(ptr, val, (unsigned long)&new->list); - - return ret == val; + return try_cmpxchg(ptr, &val, (unsigned long)&new->list); } /* @@ -3003,7 +2995,6 @@ rb_try_to_discard(struct ring_buffer_per_cpu *cpu_buffer, { unsigned long new_index, old_index; struct buffer_page *bpage; - unsigned long index; unsigned long addr; u64 write_stamp; u64 delta; @@ -3060,8 +3051,9 @@ rb_try_to_discard(struct ring_buffer_per_cpu *cpu_buffer, */ old_index += write_mask; new_index += write_mask; - index = local_cmpxchg(&bpage->write, old_index, new_index); - if (index == old_index) { + + /* caution: old_index gets updated on cmpxchg failure */ + if (local_try_cmpxchg(&bpage->write, &old_index, new_index)) { /* update counters */ local_sub(event_length, &cpu_buffer->entries_bytes); return true; -- GitLab From 9182b519b8c9733e921165f93e63cfffc18d1e0a Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Google)" Date: Sat, 15 Jul 2023 10:12:14 -0400 Subject: [PATCH 0586/3445] tracing: Remove unnecessary copying of tr->current_trace The iterator allocated a descriptor to copy the current_trace. This was done with the assumption that the function pointers might change. But this was a false assuption, as it does not change. There's no reason to make a copy of the current_trace and just use the pointer it points to. This removes needing to manage freeing the descriptor. Worse yet, there's locations that the iterator is used but does make a copy and just uses the pointer. This could cause the actual pointer to the trace descriptor to be freed and not the allocated copy. This is more of a clean up than a fix. Link: https://lkml.kernel.org/r/20230715141348.135792275@goodmis.org Cc: Mark Rutland Cc: Andrew Morton Fixes: d7350c3f45694 ("tracing/core: make the read callbacks reentrants") Reviewed-by: Masami Hiramatsu (Google) Signed-off-by: Steven Rostedt (Google) --- kernel/trace/trace.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index f6ed6b79d91f1..5e665c356df77 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -4189,15 +4189,9 @@ static void *s_start(struct seq_file *m, loff_t *pos) loff_t l = 0; int cpu; - /* - * copy the tracer to avoid using a global lock all around. - * iter->trace is a copy of current_trace, the pointer to the - * name may be used instead of a strcmp(), as iter->trace->name - * will point to the same string as current_trace->name. - */ mutex_lock(&trace_types_lock); - if (unlikely(tr->current_trace && iter->trace->name != tr->current_trace->name)) - *iter->trace = *tr->current_trace; + if (unlikely(tr->current_trace != iter->trace)) + iter->trace = tr->current_trace; mutex_unlock(&trace_types_lock); #ifdef CONFIG_TRACER_MAX_TRACE @@ -4846,16 +4840,8 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot) iter->fmt = NULL; iter->fmt_size = 0; - /* - * We make a copy of the current tracer to avoid concurrent - * changes on it while we are reading. - */ mutex_lock(&trace_types_lock); - iter->trace = kzalloc(sizeof(*iter->trace), GFP_KERNEL); - if (!iter->trace) - goto fail; - - *iter->trace = *tr->current_trace; + iter->trace = tr->current_trace; if (!zalloc_cpumask_var(&iter->started, GFP_KERNEL)) goto fail; @@ -4920,7 +4906,6 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot) fail: mutex_unlock(&trace_types_lock); - kfree(iter->trace); kfree(iter->temp); kfree(iter->buffer_iter); release: @@ -5005,7 +4990,6 @@ static int tracing_release(struct inode *inode, struct file *file) free_cpumask_var(iter->started); kfree(iter->fmt); kfree(iter->temp); - kfree(iter->trace); kfree(iter->buffer_iter); seq_release_private(inode, file); -- GitLab From 6bba92881de9dde4c07cbb24b5691eb6eb9495f2 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Google)" Date: Sat, 15 Jul 2023 10:12:15 -0400 Subject: [PATCH 0587/3445] tracing: Add free_trace_iter_content() helper function As the trace iterator is created and used by various interfaces, the clean up of it needs to be consistent. Create a free_trace_iter_content() helper function that frees the content of the iterator and use that to clean it up in all places that it is used. Link: https://lkml.kernel.org/r/20230715141348.341887497@goodmis.org Cc: Mark Rutland Cc: Andrew Morton Signed-off-by: Steven Rostedt (Google) Reviewed-by: Masami Hiramatsu (Google) Signed-off-by: Steven Rostedt (Google) --- kernel/trace/trace.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 5e665c356df77..a3c4f98268726 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -4799,6 +4799,25 @@ static const struct seq_operations tracer_seq_ops = { .show = s_show, }; +/* + * Note, as iter itself can be allocated and freed in different + * ways, this function is only used to free its content, and not + * the iterator itself. The only requirement to all the allocations + * is that it must zero all fields (kzalloc), as freeing works with + * ethier allocated content or NULL. + */ +static void free_trace_iter_content(struct trace_iterator *iter) +{ + /* The fmt is either NULL, allocated or points to static_fmt_buf */ + if (iter->fmt != static_fmt_buf) + kfree(iter->fmt); + + kfree(iter->temp); + kfree(iter->buffer_iter); + mutex_destroy(&iter->mutex); + free_cpumask_var(iter->started); +} + static struct trace_iterator * __tracing_open(struct inode *inode, struct file *file, bool snapshot) { @@ -4906,8 +4925,7 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot) fail: mutex_unlock(&trace_types_lock); - kfree(iter->temp); - kfree(iter->buffer_iter); + free_trace_iter_content(iter); release: seq_release_private(inode, file); return ERR_PTR(-ENOMEM); @@ -4986,11 +5004,7 @@ static int tracing_release(struct inode *inode, struct file *file) mutex_unlock(&trace_types_lock); - mutex_destroy(&iter->mutex); - free_cpumask_var(iter->started); - kfree(iter->fmt); - kfree(iter->temp); - kfree(iter->buffer_iter); + free_trace_iter_content(iter); seq_release_private(inode, file); return 0; @@ -6747,10 +6761,7 @@ static int tracing_release_pipe(struct inode *inode, struct file *file) mutex_unlock(&trace_types_lock); - free_cpumask_var(iter->started); - kfree(iter->fmt); - kfree(iter->temp); - mutex_destroy(&iter->mutex); + free_trace_iter_content(iter); kfree(iter); trace_array_put(tr); -- GitLab From 6d98a0f2ac3c021d21be66fa34e992137cd25bcb Mon Sep 17 00:00:00 2001 From: Zheng Yejian Date: Wed, 5 Jul 2023 08:27:05 +0800 Subject: [PATCH 0588/3445] tracing: Set actual size after ring buffer resize Currently we can resize trace ringbuffer by writing a value into file 'buffer_size_kb', then by reading the file, we get the value that is usually what we wrote. However, this value may be not actual size of trace ring buffer because of the round up when doing resize in kernel, and the actual size would be more useful. Link: https://lore.kernel.org/linux-trace-kernel/20230705002705.576633-1-zhengyejian1@huawei.com Cc: Signed-off-by: Zheng Yejian Signed-off-by: Steven Rostedt (Google) --- kernel/trace/trace.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index a3c4f98268726..bc96567dc230e 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -6286,6 +6286,15 @@ static void set_buffer_entries(struct array_buffer *buf, unsigned long val) per_cpu_ptr(buf->data, cpu)->entries = val; } +static void update_buffer_entries(struct array_buffer *buf, int cpu) +{ + if (cpu == RING_BUFFER_ALL_CPUS) { + set_buffer_entries(buf, ring_buffer_size(buf->buffer, 0)); + } else { + per_cpu_ptr(buf->data, cpu)->entries = ring_buffer_size(buf->buffer, cpu); + } +} + #ifdef CONFIG_TRACER_MAX_TRACE /* resize @tr's buffer to the size of @size_tr's entries */ static int resize_buffer_duplicate_size(struct array_buffer *trace_buf, @@ -6364,18 +6373,12 @@ static int __tracing_resize_ring_buffer(struct trace_array *tr, return ret; } - if (cpu == RING_BUFFER_ALL_CPUS) - set_buffer_entries(&tr->max_buffer, size); - else - per_cpu_ptr(tr->max_buffer.data, cpu)->entries = size; + update_buffer_entries(&tr->max_buffer, cpu); out: #endif /* CONFIG_TRACER_MAX_TRACE */ - if (cpu == RING_BUFFER_ALL_CPUS) - set_buffer_entries(&tr->array_buffer, size); - else - per_cpu_ptr(tr->array_buffer.data, cpu)->entries = size; + update_buffer_entries(&tr->array_buffer, cpu); return ret; } -- GitLab From ee41106a12c76f38d0cf82ef17809fa62757151d Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Google)" Date: Fri, 28 Jul 2023 23:50:43 +0530 Subject: [PATCH 0589/3445] tracing: Require all trace events to have a TRACE_SYSTEM The creation of the trace event directory requires that a TRACE_SYSTEM is defined that the trace event directory is added within the system it was defined in. The code handled the case where a TRACE_SYSTEM was not added, and would then add the event at the events directory. But nothing should be doing this. This code also prevents the implementation of creating dynamic dentrys for the eventfs system. As this path has never been hit on correct code, remove it. If it does get hit, issues a WARN_ON_ONCE() and return ENODEV. Link: https://lkml.kernel.org/r/1690568452-46553-2-git-send-email-akaher@vmware.com Signed-off-by: Steven Rostedt (Google) Signed-off-by: Ajay Kaher Signed-off-by: Steven Rostedt (Google) --- kernel/trace/trace_events.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 578f1f7d49a61..3ecc41f6acd96 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -2420,14 +2420,15 @@ event_create_dir(struct dentry *parent, struct trace_event_file *file) /* * If the trace point header did not define TRACE_SYSTEM - * then the system would be called "TRACE_SYSTEM". + * then the system would be called "TRACE_SYSTEM". This should + * never happen. */ - if (strcmp(call->class->system, TRACE_SYSTEM) != 0) { - d_events = event_subsystem_dir(tr, call->class->system, file, parent); - if (!d_events) - return -ENOMEM; - } else - d_events = parent; + if (WARN_ON_ONCE(strcmp(call->class->system, TRACE_SYSTEM) == 0)) + return -ENODEV; + + d_events = event_subsystem_dir(tr, call->class->system, file, parent); + if (!d_events) + return -ENOMEM; name = trace_event_name(call); file->dir = tracefs_create_dir(name, d_events); -- GitLab From ba37ff75e04be7df5fa19dcd86f81c984294a37b Mon Sep 17 00:00:00 2001 From: Ajay Kaher Date: Fri, 28 Jul 2023 23:50:44 +0530 Subject: [PATCH 0590/3445] eventfs: Implement tracefs_inode_cache Create a kmem cache of tracefs_inodes. To be more efficient, as there are lots of tracefs inodes, create its own cache. This also allows to see how many tracefs inodes have been created. Add helper functions: tracefs_alloc_inode() tracefs_free_inode() get_tracefs() Link: https://lkml.kernel.org/r/1690568452-46553-3-git-send-email-akaher@vmware.com Signed-off-by: Ajay Kaher Co-developed-by: Steven Rostedt (VMware) Signed-off-by: Steven Rostedt (VMware) Tested-by: Ching-lin Yu Signed-off-by: Steven Rostedt (Google) --- fs/tracefs/inode.c | 39 +++++++++++++++++++++++++++++++++++++++ fs/tracefs/internal.h | 15 +++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 fs/tracefs/internal.h diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c index 57ac8aa4a724d..2508944cc4d87 100644 --- a/fs/tracefs/inode.c +++ b/fs/tracefs/inode.c @@ -21,13 +21,33 @@ #include #include #include +#include "internal.h" #define TRACEFS_DEFAULT_MODE 0700 +static struct kmem_cache *tracefs_inode_cachep __ro_after_init; static struct vfsmount *tracefs_mount; static int tracefs_mount_count; static bool tracefs_registered; +static struct inode *tracefs_alloc_inode(struct super_block *sb) +{ + struct tracefs_inode *ti; + + ti = kmem_cache_alloc(tracefs_inode_cachep, GFP_KERNEL); + if (!ti) + return NULL; + + ti->flags = 0; + + return &ti->vfs_inode; +} + +static void tracefs_free_inode(struct inode *inode) +{ + kmem_cache_free(tracefs_inode_cachep, get_tracefs(inode)); +} + static ssize_t default_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -346,6 +366,9 @@ static int tracefs_show_options(struct seq_file *m, struct dentry *root) } static const struct super_operations tracefs_super_operations = { + .alloc_inode = tracefs_alloc_inode, + .free_inode = tracefs_free_inode, + .drop_inode = generic_delete_inode, .statfs = simple_statfs, .remount_fs = tracefs_remount, .show_options = tracefs_show_options, @@ -628,10 +651,26 @@ bool tracefs_initialized(void) return tracefs_registered; } +static void init_once(void *foo) +{ + struct tracefs_inode *ti = (struct tracefs_inode *) foo; + + inode_init_once(&ti->vfs_inode); +} + static int __init tracefs_init(void) { int retval; + tracefs_inode_cachep = kmem_cache_create("tracefs_inode_cache", + sizeof(struct tracefs_inode), + 0, (SLAB_RECLAIM_ACCOUNT| + SLAB_MEM_SPREAD| + SLAB_ACCOUNT), + init_once); + if (!tracefs_inode_cachep) + return -ENOMEM; + retval = sysfs_create_mount_point(kernel_kobj, "tracing"); if (retval) return -EINVAL; diff --git a/fs/tracefs/internal.h b/fs/tracefs/internal.h new file mode 100644 index 0000000000000..954ea005632b2 --- /dev/null +++ b/fs/tracefs/internal.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _TRACEFS_INTERNAL_H +#define _TRACEFS_INTERNAL_H + +struct tracefs_inode { + unsigned long flags; + void *private; + struct inode vfs_inode; +}; + +static inline struct tracefs_inode *get_tracefs(const struct inode *inode) +{ + return container_of(inode, struct tracefs_inode, vfs_inode); +} +#endif /* _TRACEFS_INTERNAL_H */ -- GitLab From 2c6b6b1029d46a8760d6cba09b4e75cb1ac9b579 Mon Sep 17 00:00:00 2001 From: Ajay Kaher Date: Fri, 28 Jul 2023 23:50:45 +0530 Subject: [PATCH 0591/3445] tracefs: Rename and export some tracefs functions Export a few tracefs functions that will be needed by the eventfs dynamic file system. Rename them to start with "tracefs_" to keep with the name space. start_creating -> tracefs_start_creating failed_creating -> tracefs_failed_creating end_creating -> tracefs_end_creating Link: https://lkml.kernel.org/r/1690568452-46553-4-git-send-email-akaher@vmware.com Signed-off-by: Ajay Kaher Co-developed-by: Steven Rostedt (VMware) Signed-off-by: Steven Rostedt (VMware) Tested-by: Ching-lin Yu Signed-off-by: Steven Rostedt (Google) --- fs/tracefs/inode.c | 20 ++++++++++---------- fs/tracefs/internal.h | 5 +++++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c index 2508944cc4d87..4acc4b4dfd22c 100644 --- a/fs/tracefs/inode.c +++ b/fs/tracefs/inode.c @@ -147,7 +147,7 @@ static const struct inode_operations tracefs_dir_inode_operations = { .rmdir = tracefs_syscall_rmdir, }; -static struct inode *tracefs_get_inode(struct super_block *sb) +struct inode *tracefs_get_inode(struct super_block *sb) { struct inode *inode = new_inode(sb); if (inode) { @@ -422,7 +422,7 @@ static struct file_system_type trace_fs_type = { }; MODULE_ALIAS_FS("tracefs"); -static struct dentry *start_creating(const char *name, struct dentry *parent) +struct dentry *tracefs_start_creating(const char *name, struct dentry *parent) { struct dentry *dentry; int error; @@ -460,7 +460,7 @@ static struct dentry *start_creating(const char *name, struct dentry *parent) return dentry; } -static struct dentry *failed_creating(struct dentry *dentry) +struct dentry *tracefs_failed_creating(struct dentry *dentry) { inode_unlock(d_inode(dentry->d_parent)); dput(dentry); @@ -468,7 +468,7 @@ static struct dentry *failed_creating(struct dentry *dentry) return NULL; } -static struct dentry *end_creating(struct dentry *dentry) +struct dentry *tracefs_end_creating(struct dentry *dentry) { inode_unlock(d_inode(dentry->d_parent)); return dentry; @@ -513,14 +513,14 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode, if (!(mode & S_IFMT)) mode |= S_IFREG; BUG_ON(!S_ISREG(mode)); - dentry = start_creating(name, parent); + dentry = tracefs_start_creating(name, parent); if (IS_ERR(dentry)) return NULL; inode = tracefs_get_inode(dentry->d_sb); if (unlikely(!inode)) - return failed_creating(dentry); + return tracefs_failed_creating(dentry); inode->i_mode = mode; inode->i_fop = fops ? fops : &tracefs_file_operations; @@ -529,13 +529,13 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode, inode->i_gid = d_inode(dentry->d_parent)->i_gid; d_instantiate(dentry, inode); fsnotify_create(d_inode(dentry->d_parent), dentry); - return end_creating(dentry); + return tracefs_end_creating(dentry); } static struct dentry *__create_dir(const char *name, struct dentry *parent, const struct inode_operations *ops) { - struct dentry *dentry = start_creating(name, parent); + struct dentry *dentry = tracefs_start_creating(name, parent); struct inode *inode; if (IS_ERR(dentry)) @@ -543,7 +543,7 @@ static struct dentry *__create_dir(const char *name, struct dentry *parent, inode = tracefs_get_inode(dentry->d_sb); if (unlikely(!inode)) - return failed_creating(dentry); + return tracefs_failed_creating(dentry); /* Do not set bits for OTH */ inode->i_mode = S_IFDIR | S_IRWXU | S_IRUSR| S_IRGRP | S_IXUSR | S_IXGRP; @@ -557,7 +557,7 @@ static struct dentry *__create_dir(const char *name, struct dentry *parent, d_instantiate(dentry, inode); inc_nlink(d_inode(dentry->d_parent)); fsnotify_mkdir(d_inode(dentry->d_parent), dentry); - return end_creating(dentry); + return tracefs_end_creating(dentry); } /** diff --git a/fs/tracefs/internal.h b/fs/tracefs/internal.h index 954ea005632b2..7dfb7ebc1c3f8 100644 --- a/fs/tracefs/internal.h +++ b/fs/tracefs/internal.h @@ -12,4 +12,9 @@ static inline struct tracefs_inode *get_tracefs(const struct inode *inode) { return container_of(inode, struct tracefs_inode, vfs_inode); } + +struct dentry *tracefs_start_creating(const char *name, struct dentry *parent); +struct dentry *tracefs_end_creating(struct dentry *dentry); +struct dentry *tracefs_failed_creating(struct dentry *dentry); +struct inode *tracefs_get_inode(struct super_block *sb); #endif /* _TRACEFS_INTERNAL_H */ -- GitLab From c1504e5102384762bd06b068e9928b624a8a88c6 Mon Sep 17 00:00:00 2001 From: Ajay Kaher Date: Fri, 28 Jul 2023 23:50:46 +0530 Subject: [PATCH 0592/3445] eventfs: Implement eventfs dir creation functions Add eventfs_file structure which will hold the properties of the eventfs files and directories. Add following functions to create the directories in eventfs: eventfs_create_events_dir() will create the top level "events" directory within the tracefs file system. eventfs_add_subsystem_dir() creates an eventfs_file descriptor with the given name of the subsystem. eventfs_add_dir() creates an eventfs_file descriptor with the given name of the directory and attached to a eventfs_file of a subsystem. Add tracefs_inode structure to hold the inodes, flags and pointers to private data used by eventfs. Link: https://lkml.kernel.org/r/1690568452-46553-5-git-send-email-akaher@vmware.com Signed-off-by: Ajay Kaher Co-developed-by: Steven Rostedt (VMware) Signed-off-by: Steven Rostedt (VMware) Tested-by: Ching-lin Yu Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-lkp/202305051619.9a469a9a-yujie.liu@intel.com Signed-off-by: Steven Rostedt (Google) --- fs/tracefs/Makefile | 1 + fs/tracefs/event_inode.c | 211 +++++++++++++++++++++++++++++++++++++++ fs/tracefs/internal.h | 4 + include/linux/tracefs.h | 11 ++ 4 files changed, 227 insertions(+) create mode 100644 fs/tracefs/event_inode.c diff --git a/fs/tracefs/Makefile b/fs/tracefs/Makefile index 7c35a282b484c..73c56da8e284e 100644 --- a/fs/tracefs/Makefile +++ b/fs/tracefs/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only tracefs-objs := inode.o +tracefs-objs += event_inode.o obj-$(CONFIG_TRACING) += tracefs.o diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c new file mode 100644 index 0000000000000..8f334b122e464 --- /dev/null +++ b/fs/tracefs/event_inode.c @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * event_inode.c - part of tracefs, a pseudo file system for activating tracing + * + * Copyright (C) 2020-23 VMware Inc, author: Steven Rostedt (VMware) + * Copyright (C) 2020-23 VMware Inc, author: Ajay Kaher + * + * eventfs is used to dynamically create inodes and dentries based on the + * meta data provided by the tracing system. + * + * eventfs stores the meta-data of files/dirs and holds off on creating + * inodes/dentries of the files. When accessed, the eventfs will create the + * inodes/dentries in a just-in-time (JIT) manner. The eventfs will clean up + * and delete the inodes/dentries when they are no longer referenced. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "internal.h" + +struct eventfs_inode { + struct list_head e_top_files; +}; + +/** + * struct eventfs_file - hold the properties of the eventfs files and + * directories. + * @name: the name of the file or directory to create + * @list: file or directory to be added to parent directory + * @ei: list of files and directories within directory + * @fop: file_operations for file or directory + * @iop: inode_operations for file or directory + * @data: something that the caller will want to get to later on + * @mode: the permission that the file or directory should have + */ +struct eventfs_file { + const char *name; + struct list_head list; + struct eventfs_inode *ei; + const struct file_operations *fop; + const struct inode_operations *iop; + void *data; + umode_t mode; +}; + +static DEFINE_MUTEX(eventfs_mutex); + +static const struct inode_operations eventfs_root_dir_inode_operations = { +}; + +static const struct file_operations eventfs_file_operations = { +}; + +/** + * eventfs_prepare_ef - helper function to prepare eventfs_file + * @name: the name of the file/directory to create. + * @mode: the permission that the file should have. + * @fop: struct file_operations that should be used for this file/directory. + * @iop: struct inode_operations that should be used for this file/directory. + * @data: something that the caller will want to get to later on. The + * inode.i_private pointer will point to this value on the open() call. + * + * This function allocates and fills the eventfs_file structure. + */ +static struct eventfs_file *eventfs_prepare_ef(const char *name, umode_t mode, + const struct file_operations *fop, + const struct inode_operations *iop, + void *data) +{ + struct eventfs_file *ef; + + ef = kzalloc(sizeof(*ef), GFP_KERNEL); + if (!ef) + return ERR_PTR(-ENOMEM); + + ef->name = kstrdup(name, GFP_KERNEL); + if (!ef->name) { + kfree(ef); + return ERR_PTR(-ENOMEM); + } + + if (S_ISDIR(mode)) { + ef->ei = kzalloc(sizeof(*ef->ei), GFP_KERNEL); + if (!ef->ei) { + kfree(ef->name); + kfree(ef); + return ERR_PTR(-ENOMEM); + } + INIT_LIST_HEAD(&ef->ei->e_top_files); + } else { + ef->ei = NULL; + } + + ef->iop = iop; + ef->fop = fop; + ef->mode = mode; + ef->data = data; + return ef; +} + +/** + * eventfs_create_events_dir - create the trace event structure + * @name: the name of the directory to create. + * @parent: parent dentry for this file. This should be a directory dentry + * if set. If this parameter is NULL, then the directory will be + * created in the root of the tracefs filesystem. + * + * This function creates the top of the trace event directory. + */ +struct dentry *eventfs_create_events_dir(const char *name, + struct dentry *parent) +{ + struct dentry *dentry = tracefs_start_creating(name, parent); + struct eventfs_inode *ei; + struct tracefs_inode *ti; + struct inode *inode; + + if (IS_ERR(dentry)) + return dentry; + + ei = kzalloc(sizeof(*ei), GFP_KERNEL); + if (!ei) + return ERR_PTR(-ENOMEM); + inode = tracefs_get_inode(dentry->d_sb); + if (unlikely(!inode)) { + kfree(ei); + tracefs_failed_creating(dentry); + return ERR_PTR(-ENOMEM); + } + + INIT_LIST_HEAD(&ei->e_top_files); + + ti = get_tracefs(inode); + ti->flags |= TRACEFS_EVENT_INODE; + ti->private = ei; + + inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; + inode->i_op = &eventfs_root_dir_inode_operations; + inode->i_fop = &eventfs_file_operations; + + /* directory inodes start off with i_nlink == 2 (for "." entry) */ + inc_nlink(inode); + d_instantiate(dentry, inode); + inc_nlink(dentry->d_parent->d_inode); + fsnotify_mkdir(dentry->d_parent->d_inode, dentry); + return tracefs_end_creating(dentry); +} + +/** + * eventfs_add_subsystem_dir - add eventfs subsystem_dir to list to create later + * @name: the name of the file to create. + * @parent: parent dentry for this dir. + * + * This function adds eventfs subsystem dir to list. + * And all these dirs are created on the fly when they are looked up, + * and the dentry and inodes will be removed when they are done. + */ +struct eventfs_file *eventfs_add_subsystem_dir(const char *name, + struct dentry *parent) +{ + struct tracefs_inode *ti_parent; + struct eventfs_inode *ei_parent; + struct eventfs_file *ef; + + if (!parent) + return ERR_PTR(-EINVAL); + + ti_parent = get_tracefs(parent->d_inode); + ei_parent = ti_parent->private; + + ef = eventfs_prepare_ef(name, S_IFDIR, NULL, NULL, NULL); + if (IS_ERR(ef)) + return ef; + + mutex_lock(&eventfs_mutex); + list_add_tail(&ef->list, &ei_parent->e_top_files); + mutex_unlock(&eventfs_mutex); + return ef; +} + +/** + * eventfs_add_dir - add eventfs dir to list to create later + * @name: the name of the file to create. + * @ef_parent: parent eventfs_file for this dir. + * + * This function adds eventfs dir to list. + * And all these dirs are created on the fly when they are looked up, + * and the dentry and inodes will be removed when they are done. + */ +struct eventfs_file *eventfs_add_dir(const char *name, + struct eventfs_file *ef_parent) +{ + struct eventfs_file *ef; + + if (!ef_parent) + return ERR_PTR(-EINVAL); + + ef = eventfs_prepare_ef(name, S_IFDIR, NULL, NULL, NULL); + if (IS_ERR(ef)) + return ef; + + mutex_lock(&eventfs_mutex); + list_add_tail(&ef->list, &ef_parent->ei->e_top_files); + mutex_unlock(&eventfs_mutex); + return ef; +} diff --git a/fs/tracefs/internal.h b/fs/tracefs/internal.h index 7dfb7ebc1c3f8..f0fd565d59ec8 100644 --- a/fs/tracefs/internal.h +++ b/fs/tracefs/internal.h @@ -2,6 +2,10 @@ #ifndef _TRACEFS_INTERNAL_H #define _TRACEFS_INTERNAL_H +enum { + TRACEFS_EVENT_INODE = BIT(1), +}; + struct tracefs_inode { unsigned long flags; void *private; diff --git a/include/linux/tracefs.h b/include/linux/tracefs.h index 99912445974ce..432e5e6f79018 100644 --- a/include/linux/tracefs.h +++ b/include/linux/tracefs.h @@ -21,6 +21,17 @@ struct file_operations; #ifdef CONFIG_TRACING +struct eventfs_file; + +struct dentry *eventfs_create_events_dir(const char *name, + struct dentry *parent); + +struct eventfs_file *eventfs_add_subsystem_dir(const char *name, + struct dentry *parent); + +struct eventfs_file *eventfs_add_dir(const char *name, + struct eventfs_file *ef_parent); + struct dentry *tracefs_create_file(const char *name, umode_t mode, struct dentry *parent, void *data, const struct file_operations *fops); -- GitLab From 88f349b4a83aab6a0fabd4230a1b6796f26bc546 Mon Sep 17 00:00:00 2001 From: Ajay Kaher Date: Fri, 28 Jul 2023 23:50:47 +0530 Subject: [PATCH 0593/3445] eventfs: Implement eventfs file add functions Add the following functions to add files to evenfs: eventfs_add_events_file() to add the data needed to create a specific file located at the top level events directory. The dentry/inode will be created when the events directory is scanned. eventfs_add_file() to add the data needed for files within the directories below the top level events directory. The dentry/inode of the file will be created when the directory that the file is in is scanned. Link: https://lkml.kernel.org/r/1690568452-46553-6-git-send-email-akaher@vmware.com Signed-off-by: Ajay Kaher Co-developed-by: Steven Rostedt (VMware) Signed-off-by: Steven Rostedt (VMware) Tested-by: Ching-lin Yu Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-lkp/202305051619.9a469a9a-yujie.liu@intel.com Signed-off-by: Steven Rostedt (Google) --- fs/tracefs/event_inode.c | 86 ++++++++++++++++++++++++++++++++++++++++ include/linux/tracefs.h | 8 ++++ 2 files changed, 94 insertions(+) diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c index 8f334b122e464..9e4843be9dc94 100644 --- a/fs/tracefs/event_inode.c +++ b/fs/tracefs/event_inode.c @@ -209,3 +209,89 @@ struct eventfs_file *eventfs_add_dir(const char *name, mutex_unlock(&eventfs_mutex); return ef; } + +/** + * eventfs_add_events_file - add the data needed to create a file for later reference + * @name: the name of the file to create. + * @mode: the permission that the file should have. + * @parent: parent dentry for this file. + * @data: something that the caller will want to get to later on. + * @fop: struct file_operations that should be used for this file. + * + * This function is used to add the information needed to create a + * dentry/inode within the top level events directory. The file created + * will have the @mode permissions. The @data will be used to fill the + * inode.i_private when the open() call is done. The dentry and inodes are + * all created when they are referenced, and removed when they are no + * longer referenced. + */ +int eventfs_add_events_file(const char *name, umode_t mode, + struct dentry *parent, void *data, + const struct file_operations *fop) +{ + struct tracefs_inode *ti; + struct eventfs_inode *ei; + struct eventfs_file *ef; + + if (!parent) + return -EINVAL; + + if (!(mode & S_IFMT)) + mode |= S_IFREG; + + if (!parent->d_inode) + return -EINVAL; + + ti = get_tracefs(parent->d_inode); + if (!(ti->flags & TRACEFS_EVENT_INODE)) + return -EINVAL; + + ei = ti->private; + ef = eventfs_prepare_ef(name, mode, fop, NULL, data); + + if (IS_ERR(ef)) + return -ENOMEM; + + mutex_lock(&eventfs_mutex); + list_add_tail(&ef->list, &ei->e_top_files); + mutex_unlock(&eventfs_mutex); + return 0; +} + +/** + * eventfs_add_file - add eventfs file to list to create later + * @name: the name of the file to create. + * @mode: the permission that the file should have. + * @ef_parent: parent eventfs_file for this file. + * @data: something that the caller will want to get to later on. + * @fop: struct file_operations that should be used for this file. + * + * This function is used to add the information needed to create a + * file within a subdirectory of the events directory. The file created + * will have the @mode permissions. The @data will be used to fill the + * inode.i_private when the open() call is done. The dentry and inodes are + * all created when they are referenced, and removed when they are no + * longer referenced. + */ +int eventfs_add_file(const char *name, umode_t mode, + struct eventfs_file *ef_parent, + void *data, + const struct file_operations *fop) +{ + struct eventfs_file *ef; + + if (!ef_parent) + return -EINVAL; + + if (!(mode & S_IFMT)) + mode |= S_IFREG; + + ef = eventfs_prepare_ef(name, mode, fop, NULL, data); + if (IS_ERR(ef)) + return -ENOMEM; + + mutex_lock(&eventfs_mutex); + list_add_tail(&ef->list, &ef_parent->ei->e_top_files); + mutex_unlock(&eventfs_mutex); + return 0; +} diff --git a/include/linux/tracefs.h b/include/linux/tracefs.h index 432e5e6f79018..54c9cbd0389b8 100644 --- a/include/linux/tracefs.h +++ b/include/linux/tracefs.h @@ -32,6 +32,14 @@ struct eventfs_file *eventfs_add_subsystem_dir(const char *name, struct eventfs_file *eventfs_add_dir(const char *name, struct eventfs_file *ef_parent); +int eventfs_add_file(const char *name, umode_t mode, + struct eventfs_file *ef_parent, void *data, + const struct file_operations *fops); + +int eventfs_add_events_file(const char *name, umode_t mode, + struct dentry *parent, void *data, + const struct file_operations *fops); + struct dentry *tracefs_create_file(const char *name, umode_t mode, struct dentry *parent, void *data, const struct file_operations *fops); -- GitLab From 63940449555e799d387f316993ad824476c16953 Mon Sep 17 00:00:00 2001 From: Ajay Kaher Date: Fri, 28 Jul 2023 23:50:48 +0530 Subject: [PATCH 0594/3445] eventfs: Implement eventfs lookup, read, open functions Add the inode_operations, file_operations, and helper functions to eventfs: dcache_dir_open_wrapper() eventfs_root_lookup() eventfs_release() eventfs_set_ef_status_free() eventfs_post_create_dir() The inode_operations and file_operations functions will be called from the VFS layer. create_file() and create_dir() are added as stub functions and will be filled in later. Link: https://lkml.kernel.org/r/1690568452-46553-7-git-send-email-akaher@vmware.com Signed-off-by: Ajay Kaher Co-developed-by: Steven Rostedt (VMware) Signed-off-by: Steven Rostedt (VMware) Tested-by: Ching-lin Yu Signed-off-by: Steven Rostedt (Google) --- fs/tracefs/event_inode.c | 304 +++++++++++++++++++++++++++++++++++++++ fs/tracefs/internal.h | 2 + 2 files changed, 306 insertions(+) diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c index 9e4843be9dc94..24d645c61029c 100644 --- a/fs/tracefs/event_inode.c +++ b/fs/tracefs/event_inode.c @@ -31,6 +31,8 @@ struct eventfs_inode { * struct eventfs_file - hold the properties of the eventfs files and * directories. * @name: the name of the file or directory to create + * @d_parent: holds parent's dentry + * @dentry: once accessed holds dentry * @list: file or directory to be added to parent directory * @ei: list of files and directories within directory * @fop: file_operations for file or directory @@ -40,22 +42,320 @@ struct eventfs_inode { */ struct eventfs_file { const char *name; + struct dentry *d_parent; + struct dentry *dentry; struct list_head list; struct eventfs_inode *ei; const struct file_operations *fop; const struct inode_operations *iop; + union { + struct list_head del_list; /* list of eventfs_file to delete */ + struct rcu_head rcu; /* eventfs_file to delete */ + unsigned long is_freed; /* Freed if one of the above is set */ + }; void *data; umode_t mode; }; static DEFINE_MUTEX(eventfs_mutex); +DEFINE_STATIC_SRCU(eventfs_srcu); + +static struct dentry *eventfs_root_lookup(struct inode *dir, + struct dentry *dentry, + unsigned int flags); +static int dcache_dir_open_wrapper(struct inode *inode, struct file *file); +static int eventfs_release(struct inode *inode, struct file *file); static const struct inode_operations eventfs_root_dir_inode_operations = { + .lookup = eventfs_root_lookup, }; static const struct file_operations eventfs_file_operations = { + .open = dcache_dir_open_wrapper, + .read = generic_read_dir, + .iterate_shared = dcache_readdir, + .llseek = generic_file_llseek, + .release = eventfs_release, +}; + +/** + * create_file - create a file in the tracefs filesystem + * @name: the name of the file to create. + * @mode: the permission that the file should have. + * @parent: parent dentry for this file. + * @data: something that the caller will want to get to later on. + * @fop: struct file_operations that should be used for this file. + * + * This is the basic "create a file" function for tracefs. It allows for a + * wide range of flexibility in creating a file. + * + * This function will return a pointer to a dentry if it succeeds. This + * pointer must be passed to the tracefs_remove() function when the file is + * to be removed (no automatic cleanup happens if your module is unloaded, + * you are responsible here.) If an error occurs, %NULL will be returned. + * + * If tracefs is not enabled in the kernel, the value -%ENODEV will be + * returned. + */ +static struct dentry *create_file(const char *name, umode_t mode, + struct dentry *parent, void *data, + const struct file_operations *fop) +{ + return NULL; }; +/** + * create_dir - create a dir in the tracefs filesystem + * @name: the name of the file to create. + * @parent: parent dentry for this file. + * @data: something that the caller will want to get to later on. + * + * This is the basic "create a dir" function for eventfs. It allows for a + * wide range of flexibility in creating a dir. + * + * This function will return a pointer to a dentry if it succeeds. This + * pointer must be passed to the tracefs_remove() function when the file is + * to be removed (no automatic cleanup happens if your module is unloaded, + * you are responsible here.) If an error occurs, %NULL will be returned. + * + * If tracefs is not enabled in the kernel, the value -%ENODEV will be + * returned. + */ +static struct dentry *create_dir(const char *name, struct dentry *parent, void *data) +{ + return NULL; +} + +/** + * eventfs_set_ef_status_free - set the ef->status to free + * @dentry: dentry who's status to be freed + * + * eventfs_set_ef_status_free will be called if no more + * references remain + */ +void eventfs_set_ef_status_free(struct dentry *dentry) +{ + struct tracefs_inode *ti_parent; + struct eventfs_file *ef; + + mutex_lock(&eventfs_mutex); + ti_parent = get_tracefs(dentry->d_parent->d_inode); + if (!ti_parent || !(ti_parent->flags & TRACEFS_EVENT_INODE)) + goto out; + + ef = dentry->d_fsdata; + if (!ef) + goto out; + + dentry->d_fsdata = NULL; + ef->dentry = NULL; +out: + mutex_unlock(&eventfs_mutex); +} + +/** + * eventfs_post_create_dir - post create dir routine + * @ef: eventfs_file of recently created dir + * + * Map the meta-data of files within an eventfs dir to their parent dentry + */ +static void eventfs_post_create_dir(struct eventfs_file *ef) +{ + struct eventfs_file *ef_child; + struct tracefs_inode *ti; + + /* srcu lock already held */ + /* fill parent-child relation */ + list_for_each_entry_srcu(ef_child, &ef->ei->e_top_files, list, + srcu_read_lock_held(&eventfs_srcu)) { + ef_child->d_parent = ef->dentry; + } + + ti = get_tracefs(ef->dentry->d_inode); + ti->private = ef->ei; +} + +/** + * create_dentry - helper function to create dentry + * @ef: eventfs_file of file or directory to create + * @parent: parent dentry + * @lookup: true if called from lookup routine + * + * Used to create a dentry for file/dir, executes post dentry creation routine + */ +static struct dentry * +create_dentry(struct eventfs_file *ef, struct dentry *parent, bool lookup) +{ + bool invalidate = false; + struct dentry *dentry; + + mutex_lock(&eventfs_mutex); + if (ef->is_freed) { + mutex_unlock(&eventfs_mutex); + return NULL; + } + if (ef->dentry) { + dentry = ef->dentry; + /* On dir open, up the ref count */ + if (!lookup) + dget(dentry); + mutex_unlock(&eventfs_mutex); + return dentry; + } + mutex_unlock(&eventfs_mutex); + + if (!lookup) + inode_lock(parent->d_inode); + + if (ef->ei) + dentry = create_dir(ef->name, parent, ef->data); + else + dentry = create_file(ef->name, ef->mode, parent, + ef->data, ef->fop); + + if (!lookup) + inode_unlock(parent->d_inode); + + mutex_lock(&eventfs_mutex); + if (IS_ERR_OR_NULL(dentry)) { + /* If the ef was already updated get it */ + dentry = ef->dentry; + if (dentry && !lookup) + dget(dentry); + mutex_unlock(&eventfs_mutex); + return dentry; + } + + if (!ef->dentry && !ef->is_freed) { + ef->dentry = dentry; + if (ef->ei) + eventfs_post_create_dir(ef); + dentry->d_fsdata = ef; + } else { + /* A race here, should try again (unless freed) */ + invalidate = true; + } + mutex_unlock(&eventfs_mutex); + if (invalidate) + d_invalidate(dentry); + + if (lookup || invalidate) + dput(dentry); + + return invalidate ? NULL : dentry; +} + +static bool match_event_file(struct eventfs_file *ef, const char *name) +{ + bool ret; + + mutex_lock(&eventfs_mutex); + ret = !ef->is_freed && strcmp(ef->name, name) == 0; + mutex_unlock(&eventfs_mutex); + + return ret; +} + +/** + * eventfs_root_lookup - lookup routine to create file/dir + * @dir: in which a lookup is being done + * @dentry: file/dir dentry + * @flags: to pass as flags parameter to simple lookup + * + * Used to create a dynamic file/dir within @dir. Use the eventfs_inode + * list of meta data to find the information needed to create the file/dir. + */ +static struct dentry *eventfs_root_lookup(struct inode *dir, + struct dentry *dentry, + unsigned int flags) +{ + struct tracefs_inode *ti; + struct eventfs_inode *ei; + struct eventfs_file *ef; + struct dentry *ret = NULL; + int idx; + + ti = get_tracefs(dir); + if (!(ti->flags & TRACEFS_EVENT_INODE)) + return NULL; + + ei = ti->private; + idx = srcu_read_lock(&eventfs_srcu); + list_for_each_entry_srcu(ef, &ei->e_top_files, list, + srcu_read_lock_held(&eventfs_srcu)) { + if (!match_event_file(ef, dentry->d_name.name)) + continue; + ret = simple_lookup(dir, dentry, flags); + create_dentry(ef, ef->d_parent, true); + break; + } + srcu_read_unlock(&eventfs_srcu, idx); + return ret; +} + +/** + * eventfs_release - called to release eventfs file/dir + * @inode: inode to be released + * @file: file to be released (not used) + */ +static int eventfs_release(struct inode *inode, struct file *file) +{ + struct tracefs_inode *ti; + struct eventfs_inode *ei; + struct eventfs_file *ef; + struct dentry *dentry; + int idx; + + ti = get_tracefs(inode); + if (!(ti->flags & TRACEFS_EVENT_INODE)) + return -EINVAL; + + ei = ti->private; + idx = srcu_read_lock(&eventfs_srcu); + list_for_each_entry_srcu(ef, &ei->e_top_files, list, + srcu_read_lock_held(&eventfs_srcu)) { + mutex_lock(&eventfs_mutex); + dentry = ef->dentry; + mutex_unlock(&eventfs_mutex); + if (dentry) + dput(dentry); + } + srcu_read_unlock(&eventfs_srcu, idx); + return dcache_dir_close(inode, file); +} + +/** + * dcache_dir_open_wrapper - eventfs open wrapper + * @inode: not used + * @file: dir to be opened (to create its child) + * + * Used to dynamically create the file/dir within @file. @file is really a + * directory and all the files/dirs of the children within @file will be + * created. If any of the files/dirs have already been created, their + * reference count will be incremented. + */ +static int dcache_dir_open_wrapper(struct inode *inode, struct file *file) +{ + struct tracefs_inode *ti; + struct eventfs_inode *ei; + struct eventfs_file *ef; + struct dentry *dentry = file_dentry(file); + struct inode *f_inode = file_inode(file); + int idx; + + ti = get_tracefs(f_inode); + if (!(ti->flags & TRACEFS_EVENT_INODE)) + return -EINVAL; + + ei = ti->private; + idx = srcu_read_lock(&eventfs_srcu); + list_for_each_entry_rcu(ef, &ei->e_top_files, list) { + create_dentry(ef, dentry, false); + } + srcu_read_unlock(&eventfs_srcu, idx); + return dcache_dir_open(inode, file); +} + /** * eventfs_prepare_ef - helper function to prepare eventfs_file * @name: the name of the file/directory to create. @@ -179,6 +479,7 @@ struct eventfs_file *eventfs_add_subsystem_dir(const char *name, mutex_lock(&eventfs_mutex); list_add_tail(&ef->list, &ei_parent->e_top_files); + ef->d_parent = parent; mutex_unlock(&eventfs_mutex); return ef; } @@ -206,6 +507,7 @@ struct eventfs_file *eventfs_add_dir(const char *name, mutex_lock(&eventfs_mutex); list_add_tail(&ef->list, &ef_parent->ei->e_top_files); + ef->d_parent = ef_parent->dentry; mutex_unlock(&eventfs_mutex); return ef; } @@ -254,6 +556,7 @@ int eventfs_add_events_file(const char *name, umode_t mode, mutex_lock(&eventfs_mutex); list_add_tail(&ef->list, &ei->e_top_files); + ef->d_parent = parent; mutex_unlock(&eventfs_mutex); return 0; } @@ -292,6 +595,7 @@ int eventfs_add_file(const char *name, umode_t mode, mutex_lock(&eventfs_mutex); list_add_tail(&ef->list, &ef_parent->ei->e_top_files); + ef->d_parent = ef_parent->dentry; mutex_unlock(&eventfs_mutex); return 0; } diff --git a/fs/tracefs/internal.h b/fs/tracefs/internal.h index f0fd565d59ec8..9bfad9d95a4ab 100644 --- a/fs/tracefs/internal.h +++ b/fs/tracefs/internal.h @@ -21,4 +21,6 @@ struct dentry *tracefs_start_creating(const char *name, struct dentry *parent); struct dentry *tracefs_end_creating(struct dentry *dentry); struct dentry *tracefs_failed_creating(struct dentry *dentry); struct inode *tracefs_get_inode(struct super_block *sb); +void eventfs_set_ef_status_free(struct dentry *dentry); + #endif /* _TRACEFS_INTERNAL_H */ -- GitLab From a3760079177765b7f1782419f1c3e12facaf1e9d Mon Sep 17 00:00:00 2001 From: Ajay Kaher Date: Fri, 28 Jul 2023 23:50:49 +0530 Subject: [PATCH 0595/3445] eventfs: Implement functions to create files and dirs when accessed Add create_file() and create_dir() functions to create the files and directories respectively when they are accessed. The functions will be called from the lookup operation of the inode_operations or from the open function of file_operations. Link: https://lkml.kernel.org/r/1690568452-46553-8-git-send-email-akaher@vmware.com Signed-off-by: Ajay Kaher Co-developed-by: Steven Rostedt (VMware) Signed-off-by: Steven Rostedt (VMware) Tested-by: Ching-lin Yu Signed-off-by: Steven Rostedt (Google) --- fs/tracefs/event_inode.c | 61 +++++++++++++++++++++++++++++++-- fs/tracefs/inode.c | 74 ++++++++++++++++++++++++++++++++++++++++ fs/tracefs/internal.h | 3 ++ 3 files changed, 136 insertions(+), 2 deletions(-) diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c index 24d645c61029c..5240bd2c81e78 100644 --- a/fs/tracefs/event_inode.c +++ b/fs/tracefs/event_inode.c @@ -101,7 +101,34 @@ static struct dentry *create_file(const char *name, umode_t mode, struct dentry *parent, void *data, const struct file_operations *fop) { - return NULL; + struct tracefs_inode *ti; + struct dentry *dentry; + struct inode *inode; + + if (!(mode & S_IFMT)) + mode |= S_IFREG; + + if (WARN_ON_ONCE(!S_ISREG(mode))) + return NULL; + + dentry = eventfs_start_creating(name, parent); + + if (IS_ERR(dentry)) + return dentry; + + inode = tracefs_get_inode(dentry->d_sb); + if (unlikely(!inode)) + return eventfs_failed_creating(dentry); + + inode->i_mode = mode; + inode->i_fop = fop; + inode->i_private = data; + + ti = get_tracefs(inode); + ti->flags |= TRACEFS_EVENT_INODE; + d_instantiate(dentry, inode); + fsnotify_create(dentry->d_parent->d_inode, dentry); + return eventfs_end_creating(dentry); }; /** @@ -123,7 +150,31 @@ static struct dentry *create_file(const char *name, umode_t mode, */ static struct dentry *create_dir(const char *name, struct dentry *parent, void *data) { - return NULL; + struct tracefs_inode *ti; + struct dentry *dentry; + struct inode *inode; + + dentry = eventfs_start_creating(name, parent); + if (IS_ERR(dentry)) + return dentry; + + inode = tracefs_get_inode(dentry->d_sb); + if (unlikely(!inode)) + return eventfs_failed_creating(dentry); + + inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; + inode->i_op = &eventfs_root_dir_inode_operations; + inode->i_fop = &eventfs_file_operations; + inode->i_private = data; + + ti = get_tracefs(inode); + ti->flags |= TRACEFS_EVENT_INODE; + + inc_nlink(inode); + d_instantiate(dentry, inode); + inc_nlink(dentry->d_parent->d_inode); + fsnotify_mkdir(dentry->d_parent->d_inode, dentry); + return eventfs_end_creating(dentry); } /** @@ -234,6 +285,12 @@ create_dentry(struct eventfs_file *ef, struct dentry *parent, bool lookup) } else { /* A race here, should try again (unless freed) */ invalidate = true; + + /* + * Should never happen unless we get here due to being freed. + * Otherwise it means two dentries exist with the same name. + */ + WARN_ON_ONCE(!ef->is_freed); } mutex_unlock(&eventfs_mutex); if (invalidate) diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c index 4acc4b4dfd22c..d9273066f25f5 100644 --- a/fs/tracefs/inode.c +++ b/fs/tracefs/inode.c @@ -474,6 +474,80 @@ struct dentry *tracefs_end_creating(struct dentry *dentry) return dentry; } +/** + * eventfs_start_creating - start the process of creating a dentry + * @name: Name of the file created for the dentry + * @parent: The parent dentry where this dentry will be created + * + * This is a simple helper function for the dynamically created eventfs + * files. When the directory of the eventfs files are accessed, their + * dentries are created on the fly. This function is used to start that + * process. + */ +struct dentry *eventfs_start_creating(const char *name, struct dentry *parent) +{ + struct dentry *dentry; + int error; + + error = simple_pin_fs(&trace_fs_type, &tracefs_mount, + &tracefs_mount_count); + if (error) + return ERR_PTR(error); + + /* + * If the parent is not specified, we create it in the root. + * We need the root dentry to do this, which is in the super + * block. A pointer to that is in the struct vfsmount that we + * have around. + */ + if (!parent) + parent = tracefs_mount->mnt_root; + + if (unlikely(IS_DEADDIR(parent->d_inode))) + dentry = ERR_PTR(-ENOENT); + else + dentry = lookup_one_len(name, parent, strlen(name)); + + if (!IS_ERR(dentry) && dentry->d_inode) { + dput(dentry); + dentry = ERR_PTR(-EEXIST); + } + + if (IS_ERR(dentry)) + simple_release_fs(&tracefs_mount, &tracefs_mount_count); + + return dentry; +} + +/** + * eventfs_failed_creating - clean up a failed eventfs dentry creation + * @dentry: The dentry to clean up + * + * If after calling eventfs_start_creating(), a failure is detected, the + * resources created by eventfs_start_creating() needs to be cleaned up. In + * that case, this function should be called to perform that clean up. + */ +struct dentry *eventfs_failed_creating(struct dentry *dentry) +{ + dput(dentry); + simple_release_fs(&tracefs_mount, &tracefs_mount_count); + return NULL; +} + +/** + * eventfs_end_creating - Finish the process of creating a eventfs dentry + * @dentry: The dentry that has successfully been created. + * + * This function is currently just a place holder to match + * eventfs_start_creating(). In case any synchronization needs to be added, + * this function will be used to implement that without having to modify + * the callers of eventfs_start_creating(). + */ +struct dentry *eventfs_end_creating(struct dentry *dentry) +{ + return dentry; +} + /** * tracefs_create_file - create a file in the tracefs filesystem * @name: a pointer to a string containing the name of the file to create. diff --git a/fs/tracefs/internal.h b/fs/tracefs/internal.h index 9bfad9d95a4ab..69c2b1d87c464 100644 --- a/fs/tracefs/internal.h +++ b/fs/tracefs/internal.h @@ -21,6 +21,9 @@ struct dentry *tracefs_start_creating(const char *name, struct dentry *parent); struct dentry *tracefs_end_creating(struct dentry *dentry); struct dentry *tracefs_failed_creating(struct dentry *dentry); struct inode *tracefs_get_inode(struct super_block *sb); +struct dentry *eventfs_start_creating(const char *name, struct dentry *parent); +struct dentry *eventfs_failed_creating(struct dentry *dentry); +struct dentry *eventfs_end_creating(struct dentry *dentry); void eventfs_set_ef_status_free(struct dentry *dentry); #endif /* _TRACEFS_INTERNAL_H */ -- GitLab From 5bdcd5f5331a276a3ddf1fba8605986d0d15298a Mon Sep 17 00:00:00 2001 From: Ajay Kaher Date: Fri, 28 Jul 2023 23:50:50 +0530 Subject: [PATCH 0596/3445] eventfs: Implement removal of meta data from eventfs When events are removed from tracefs, the eventfs must be aware of this. The eventfs_remove() removes the meta data from eventfs so that it will no longer create the files associated with that event. When an instance is removed from tracefs, eventfs_remove_events_dir() will remove and clean up the entire "events" directory. The helper function eventfs_remove_rec() is used to clean up and free the associated data from eventfs for both of the added functions. SRCU is used to protect the lists of meta data stored in the eventfs. The eventfs_mutex is used to protect the content of the items in the list. As lookups may be happening as deletions of events are made, the freeing of dentry/inodes and relative information is done after the SRCU grace period has passed. Link: https://lkml.kernel.org/r/1690568452-46553-9-git-send-email-akaher@vmware.com Signed-off-by: Ajay Kaher Co-developed-by: Steven Rostedt (VMware) Signed-off-by: Steven Rostedt (VMware) Tested-by: Ching-lin Yu Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202305030611.Kas747Ev-lkp@intel.com/ Signed-off-by: Steven Rostedt (Google) --- fs/tracefs/event_inode.c | 143 +++++++++++++++++++++++++++++++++++++++ include/linux/tracefs.h | 4 ++ 2 files changed, 147 insertions(+) diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c index 5240bd2c81e78..da8d2e73cc472 100644 --- a/fs/tracefs/event_inode.c +++ b/fs/tracefs/event_inode.c @@ -198,6 +198,14 @@ void eventfs_set_ef_status_free(struct dentry *dentry) if (!ef) goto out; + /* + * If ef was freed, then the LSB bit is set for d_fsdata. + * But this should not happen, as it should still have a + * ref count that prevents it. Warn in case it does. + */ + if (WARN_ON_ONCE((unsigned long)ef & 1)) + goto out; + dentry->d_fsdata = NULL; ef->dentry = NULL; out: @@ -656,3 +664,138 @@ int eventfs_add_file(const char *name, umode_t mode, mutex_unlock(&eventfs_mutex); return 0; } + +static void free_ef(struct rcu_head *head) +{ + struct eventfs_file *ef = container_of(head, struct eventfs_file, rcu); + + kfree(ef->name); + kfree(ef->ei); + kfree(ef); +} + +/** + * eventfs_remove_rec - remove eventfs dir or file from list + * @ef: eventfs_file to be removed. + * @head: to create list of eventfs_file to be deleted + * @level: to check recursion depth + * + * The helper function eventfs_remove_rec() is used to clean up and free the + * associated data from eventfs for both of the added functions. + */ +static void eventfs_remove_rec(struct eventfs_file *ef, struct list_head *head, int level) +{ + struct eventfs_file *ef_child; + + if (!ef) + return; + /* + * Check recursion depth. It should never be greater than 3: + * 0 - events/ + * 1 - events/group/ + * 2 - events/group/event/ + * 3 - events/group/event/file + */ + if (WARN_ON_ONCE(level > 3)) + return; + + if (ef->ei) { + /* search for nested folders or files */ + list_for_each_entry_srcu(ef_child, &ef->ei->e_top_files, list, + lockdep_is_held(&eventfs_mutex)) { + eventfs_remove_rec(ef_child, head, level + 1); + } + } + + list_del_rcu(&ef->list); + list_add_tail(&ef->del_list, head); +} + +/** + * eventfs_remove - remove eventfs dir or file from list + * @ef: eventfs_file to be removed. + * + * This function acquire the eventfs_mutex lock and call eventfs_remove_rec() + */ +void eventfs_remove(struct eventfs_file *ef) +{ + struct eventfs_file *tmp; + LIST_HEAD(ef_del_list); + struct dentry *dentry_list = NULL; + struct dentry *dentry; + + if (!ef) + return; + + mutex_lock(&eventfs_mutex); + eventfs_remove_rec(ef, &ef_del_list, 0); + list_for_each_entry_safe(ef, tmp, &ef_del_list, del_list) { + if (ef->dentry) { + unsigned long ptr = (unsigned long)dentry_list; + + /* Keep the dentry from being freed yet */ + dget(ef->dentry); + + /* + * Paranoid: The dget() above should prevent the dentry + * from being freed and calling eventfs_set_ef_status_free(). + * But just in case, set the link list LSB pointer to 1 + * and have eventfs_set_ef_status_free() check that to + * make sure that if it does happen, it will not think + * the d_fsdata is an event_file. + * + * For this to work, no event_file should be allocated + * on a odd space, as the ef should always be allocated + * to be at least word aligned. Check for that too. + */ + WARN_ON_ONCE(ptr & 1); + + ef->dentry->d_fsdata = (void *)(ptr | 1); + dentry_list = ef->dentry; + ef->dentry = NULL; + } + call_srcu(&eventfs_srcu, &ef->rcu, free_ef); + } + mutex_unlock(&eventfs_mutex); + + while (dentry_list) { + unsigned long ptr; + + dentry = dentry_list; + ptr = (unsigned long)dentry->d_fsdata & ~1UL; + dentry_list = (struct dentry *)ptr; + dentry->d_fsdata = NULL; + d_invalidate(dentry); + mutex_lock(&eventfs_mutex); + /* dentry should now have at least a single reference */ + WARN_ONCE((int)d_count(dentry) < 1, + "dentry %p less than one reference (%d) after invalidate\n", + dentry, d_count(dentry)); + mutex_unlock(&eventfs_mutex); + dput(dentry); + } +} + +/** + * eventfs_remove_events_dir - remove eventfs dir or file from list + * @dentry: events's dentry to be removed. + * + * This function remove events main directory + */ +void eventfs_remove_events_dir(struct dentry *dentry) +{ + struct tracefs_inode *ti; + struct eventfs_inode *ei; + + if (!dentry || !dentry->d_inode) + return; + + ti = get_tracefs(dentry->d_inode); + if (!ti || !(ti->flags & TRACEFS_EVENT_INODE)) + return; + + ei = ti->private; + d_invalidate(dentry); + dput(dentry); + kfree(ei); +} diff --git a/include/linux/tracefs.h b/include/linux/tracefs.h index 54c9cbd0389b8..009072792fa36 100644 --- a/include/linux/tracefs.h +++ b/include/linux/tracefs.h @@ -40,6 +40,10 @@ int eventfs_add_events_file(const char *name, umode_t mode, struct dentry *parent, void *data, const struct file_operations *fops); +void eventfs_remove(struct eventfs_file *ef); + +void eventfs_remove_events_dir(struct dentry *dentry); + struct dentry *tracefs_create_file(const char *name, umode_t mode, struct dentry *parent, void *data, const struct file_operations *fops); -- GitLab From a45e5f1859579f88df624997c38c05706f9015e3 Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Fri, 28 Jul 2023 14:51:39 +0800 Subject: [PATCH 0597/3445] RDMA/mlx: Remove unnecessary variable initializations Remove unnecessary variable initializations. Signed-off-by: Ruan Jinjie Link: https://lore.kernel.org/r/20230728065139.3411703-1-ruanjinjie@huawei.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/mlx4/main.c | 44 +++++++++++++++---------------- drivers/infiniband/hw/mlx5/mad.c | 40 ++++++++++++++-------------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index b18e9f2adc82d..216aacd72e4fc 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -132,7 +132,7 @@ static struct net_device *mlx4_ib_get_netdev(struct ib_device *device, if (dev) { if (mlx4_is_bonded(ibdev->dev)) { - struct net_device *upper = NULL; + struct net_device *upper; upper = netdev_master_upper_dev_get_rcu(dev); if (upper) { @@ -254,7 +254,7 @@ static int mlx4_ib_add_gid(const struct ib_gid_attr *attr, void **context) int ret = 0; int hw_update = 0; int i; - struct gid_entry *gids = NULL; + struct gid_entry *gids; u16 vlan_id = 0xffff; u8 mac[ETH_ALEN]; @@ -345,7 +345,7 @@ static int mlx4_ib_del_gid(const struct ib_gid_attr *attr, void **context) struct mlx4_port_gid_table *port_gid_table; int ret = 0; int hw_update = 0; - struct gid_entry *gids = NULL; + struct gid_entry *gids; if (!rdma_cap_roce_gid_table(attr->device, attr->port_num)) return -EINVAL; @@ -431,8 +431,8 @@ static int mlx4_ib_query_device(struct ib_device *ibdev, struct ib_udata *uhw) { struct mlx4_ib_dev *dev = to_mdev(ibdev); - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; + struct ib_smp *in_mad; + struct ib_smp *out_mad; int err; int have_ib_ports; struct mlx4_uverbs_ex_query_device cmd; @@ -649,8 +649,8 @@ mlx4_ib_port_link_layer(struct ib_device *device, u32 port_num) static int ib_link_query_port(struct ib_device *ibdev, u32 port, struct ib_port_attr *props, int netw_view) { - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; + struct ib_smp *in_mad; + struct ib_smp *out_mad; int ext_active_speed; int mad_ifc_flags = MLX4_MAD_IFC_IGNORE_KEYS; int err = -ENOMEM; @@ -827,8 +827,8 @@ static int mlx4_ib_query_port(struct ib_device *ibdev, u32 port, int __mlx4_ib_query_gid(struct ib_device *ibdev, u32 port, int index, union ib_gid *gid, int netw_view) { - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; + struct ib_smp *in_mad; + struct ib_smp *out_mad; int err = -ENOMEM; struct mlx4_ib_dev *dev = to_mdev(ibdev); int clear = 0; @@ -892,8 +892,8 @@ static int mlx4_ib_query_sl2vl(struct ib_device *ibdev, u32 port, u64 *sl2vl_tbl) { union sl2vl_tbl_to_u64 sl2vl64; - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; + struct ib_smp *in_mad; + struct ib_smp *out_mad; int mad_ifc_flags = MLX4_MAD_IFC_IGNORE_KEYS; int err = -ENOMEM; int jj; @@ -952,8 +952,8 @@ static void mlx4_init_sl2vl_tbl(struct mlx4_ib_dev *mdev) int __mlx4_ib_query_pkey(struct ib_device *ibdev, u32 port, u16 index, u16 *pkey, int netw_view) { - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; + struct ib_smp *in_mad; + struct ib_smp *out_mad; int mad_ifc_flags = MLX4_MAD_IFC_IGNORE_KEYS; int err = -ENOMEM; @@ -1968,8 +1968,8 @@ static int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) static int init_node_data(struct mlx4_ib_dev *dev) { - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; + struct ib_smp *in_mad; + struct ib_smp *out_mad; int mad_ifc_flags = MLX4_MAD_IFC_IGNORE_KEYS; int err = -ENOMEM; @@ -2621,7 +2621,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) int num_req_counters; int allocated; u32 counter_index; - struct counter_index *new_counter_index = NULL; + struct counter_index *new_counter_index; pr_info_once("%s", mlx4_ib_version); @@ -2923,7 +2923,7 @@ int mlx4_ib_steer_qp_reg(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp, { int err; size_t flow_size; - struct ib_flow_attr *flow = NULL; + struct ib_flow_attr *flow; struct ib_flow_spec_ib *ib_spec; if (is_attach) { @@ -2943,11 +2943,11 @@ int mlx4_ib_steer_qp_reg(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp, err = __mlx4_ib_create_flow(&mqp->ibqp, flow, MLX4_DOMAIN_NIC, MLX4_FS_REGULAR, &mqp->reg_id); - } else { - err = __mlx4_ib_destroy_flow(mdev->dev, mqp->reg_id); + kfree(flow); + return err; } - kfree(flow); - return err; + + return __mlx4_ib_destroy_flow(mdev->dev, mqp->reg_id); } static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr) @@ -2992,7 +2992,7 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr) static void do_slave_init(struct mlx4_ib_dev *ibdev, int slave, int do_init) { - struct mlx4_ib_demux_work **dm = NULL; + struct mlx4_ib_demux_work **dm; struct mlx4_dev *dev = ibdev->dev; int i; unsigned long flags; diff --git a/drivers/infiniband/hw/mlx5/mad.c b/drivers/infiniband/hw/mlx5/mad.c index 9c8a7b206dcf4..8102ef113b7e0 100644 --- a/drivers/infiniband/hw/mlx5/mad.c +++ b/drivers/infiniband/hw/mlx5/mad.c @@ -308,8 +308,8 @@ int mlx5_ib_process_mad(struct ib_device *ibdev, int mad_flags, u32 port_num, int mlx5_query_ext_port_caps(struct mlx5_ib_dev *dev, unsigned int port) { - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; + struct ib_smp *in_mad; + struct ib_smp *out_mad; int err = -ENOMEM; u16 packet_error; @@ -338,8 +338,8 @@ out: static int mlx5_query_mad_ifc_smp_attr_node_info(struct ib_device *ibdev, struct ib_smp *out_mad) { - struct ib_smp *in_mad = NULL; - int err = -ENOMEM; + struct ib_smp *in_mad; + int err; in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL); if (!in_mad) @@ -358,8 +358,8 @@ static int mlx5_query_mad_ifc_smp_attr_node_info(struct ib_device *ibdev, int mlx5_query_mad_ifc_system_image_guid(struct ib_device *ibdev, __be64 *sys_image_guid) { - struct ib_smp *out_mad = NULL; - int err = -ENOMEM; + struct ib_smp *out_mad; + int err; out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL); if (!out_mad) @@ -380,8 +380,8 @@ out: int mlx5_query_mad_ifc_max_pkeys(struct ib_device *ibdev, u16 *max_pkeys) { - struct ib_smp *out_mad = NULL; - int err = -ENOMEM; + struct ib_smp *out_mad; + int err; out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL); if (!out_mad) @@ -402,8 +402,8 @@ out: int mlx5_query_mad_ifc_vendor_id(struct ib_device *ibdev, u32 *vendor_id) { - struct ib_smp *out_mad = NULL; - int err = -ENOMEM; + struct ib_smp *out_mad; + int err; out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL); if (!out_mad) @@ -423,8 +423,8 @@ out: int mlx5_query_mad_ifc_node_desc(struct mlx5_ib_dev *dev, char *node_desc) { - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; + struct ib_smp *in_mad; + struct ib_smp *out_mad; int err = -ENOMEM; in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL); @@ -448,8 +448,8 @@ out: int mlx5_query_mad_ifc_node_guid(struct mlx5_ib_dev *dev, __be64 *node_guid) { - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; + struct ib_smp *in_mad; + struct ib_smp *out_mad; int err = -ENOMEM; in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL); @@ -474,8 +474,8 @@ out: int mlx5_query_mad_ifc_pkey(struct ib_device *ibdev, u32 port, u16 index, u16 *pkey) { - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; + struct ib_smp *in_mad; + struct ib_smp *out_mad; int err = -ENOMEM; in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL); @@ -503,8 +503,8 @@ out: int mlx5_query_mad_ifc_gids(struct ib_device *ibdev, u32 port, int index, union ib_gid *gid) { - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; + struct ib_smp *in_mad; + struct ib_smp *out_mad; int err = -ENOMEM; in_mad = kzalloc(sizeof(*in_mad), GFP_KERNEL); @@ -545,8 +545,8 @@ int mlx5_query_mad_ifc_port(struct ib_device *ibdev, u32 port, { struct mlx5_ib_dev *dev = to_mdev(ibdev); struct mlx5_core_dev *mdev = dev->mdev; - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; + struct ib_smp *in_mad; + struct ib_smp *out_mad; int ext_active_speed; int err = -ENOMEM; -- GitLab From 91f36237b4b9bdce7610c7450a906d46704a566a Mon Sep 17 00:00:00 2001 From: Bernard Metzler Date: Fri, 28 Jul 2023 13:44:18 +0200 Subject: [PATCH 0598/3445] RDMA/siw: Fix tx thread initialization. Immediately removing the siw module after insertion may crash in siw_stop_tx_thread(), if the according thread did not yet had a chance to initialize its wait queue and siw_stop_tx_thread() tries to wakeup that thread. Initializing the threads state before spwaning it fixes it. Reported-by: Guoqing Jiang Signed-off-by: Bernard Metzler Link: https://lore.kernel.org/r/20230728114418.124328-1-bmt@zurich.ibm.com Tested-by: Guoqing Jiang Signed-off-by: Leon Romanovsky --- drivers/infiniband/sw/siw/siw.h | 3 +- drivers/infiniband/sw/siw/siw_main.c | 40 ++---------------------- drivers/infiniband/sw/siw/siw_qp_tx.c | 44 +++++++++++++++++++++++---- 3 files changed, 43 insertions(+), 44 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw.h b/drivers/infiniband/sw/siw/siw.h index 8b4a710b82bc1..58dddb143b9f0 100644 --- a/drivers/infiniband/sw/siw/siw.h +++ b/drivers/infiniband/sw/siw/siw.h @@ -531,11 +531,12 @@ void siw_qp_llp_data_ready(struct sock *sk); void siw_qp_llp_write_space(struct sock *sk); /* QP TX path functions */ +int siw_create_tx_threads(void); +void siw_stop_tx_threads(void); int siw_run_sq(void *arg); int siw_qp_sq_process(struct siw_qp *qp); int siw_sq_start(struct siw_qp *qp); int siw_activate_tx(struct siw_qp *qp); -void siw_stop_tx_thread(int nr_cpu); int siw_get_tx_cpu(struct siw_device *sdev); void siw_put_tx_cpu(int cpu); diff --git a/drivers/infiniband/sw/siw/siw_main.c b/drivers/infiniband/sw/siw/siw_main.c index f45600d169ae7..d4b6e0106851d 100644 --- a/drivers/infiniband/sw/siw/siw_main.c +++ b/drivers/infiniband/sw/siw/siw_main.c @@ -87,29 +87,6 @@ static void siw_device_cleanup(struct ib_device *base_dev) xa_destroy(&sdev->mem_xa); } -static int siw_create_tx_threads(void) -{ - int cpu, assigned = 0; - - for_each_online_cpu(cpu) { - /* Skip HT cores */ - if (cpu % cpumask_weight(topology_sibling_cpumask(cpu))) - continue; - - siw_tx_thread[cpu] = - kthread_run_on_cpu(siw_run_sq, - (unsigned long *)(long)cpu, - cpu, "siw_tx/%u"); - if (IS_ERR(siw_tx_thread[cpu])) { - siw_tx_thread[cpu] = NULL; - continue; - } - - assigned++; - } - return assigned; -} - static int siw_dev_qualified(struct net_device *netdev) { /* @@ -529,7 +506,6 @@ static struct rdma_link_ops siw_link_ops = { static __init int siw_init_module(void) { int rv; - int nr_cpu; if (SENDPAGE_THRESH < SIW_MAX_INLINE) { pr_info("siw: sendpage threshold too small: %u\n", @@ -574,12 +550,8 @@ static __init int siw_init_module(void) return 0; out_error: - for (nr_cpu = 0; nr_cpu < nr_cpu_ids; nr_cpu++) { - if (siw_tx_thread[nr_cpu]) { - siw_stop_tx_thread(nr_cpu); - siw_tx_thread[nr_cpu] = NULL; - } - } + siw_stop_tx_threads(); + if (siw_crypto_shash) crypto_free_shash(siw_crypto_shash); @@ -593,14 +565,8 @@ out_error: static void __exit siw_exit_module(void) { - int cpu; + siw_stop_tx_threads(); - for_each_possible_cpu(cpu) { - if (siw_tx_thread[cpu]) { - siw_stop_tx_thread(cpu); - siw_tx_thread[cpu] = NULL; - } - } unregister_netdevice_notifier(&siw_netdev_nb); rdma_link_unregister(&siw_link_ops); ib_unregister_driver(RDMA_DRIVER_SIW); diff --git a/drivers/infiniband/sw/siw/siw_qp_tx.c b/drivers/infiniband/sw/siw/siw_qp_tx.c index 7c7a51d36d0cd..3ff339eceec31 100644 --- a/drivers/infiniband/sw/siw/siw_qp_tx.c +++ b/drivers/infiniband/sw/siw/siw_qp_tx.c @@ -1208,10 +1208,45 @@ struct tx_task_t { static DEFINE_PER_CPU(struct tx_task_t, siw_tx_task_g); -void siw_stop_tx_thread(int nr_cpu) +int siw_create_tx_threads(void) { - kthread_stop(siw_tx_thread[nr_cpu]); - wake_up(&per_cpu(siw_tx_task_g, nr_cpu).waiting); + int cpu, assigned = 0; + + for_each_online_cpu(cpu) { + struct tx_task_t *tx_task; + + /* Skip HT cores */ + if (cpu % cpumask_weight(topology_sibling_cpumask(cpu))) + continue; + + tx_task = &per_cpu(siw_tx_task_g, cpu); + init_llist_head(&tx_task->active); + init_waitqueue_head(&tx_task->waiting); + + siw_tx_thread[cpu] = + kthread_run_on_cpu(siw_run_sq, + (unsigned long *)(long)cpu, + cpu, "siw_tx/%u"); + if (IS_ERR(siw_tx_thread[cpu])) { + siw_tx_thread[cpu] = NULL; + continue; + } + assigned++; + } + return assigned; +} + +void siw_stop_tx_threads(void) +{ + int cpu; + + for_each_possible_cpu(cpu) { + if (siw_tx_thread[cpu]) { + kthread_stop(siw_tx_thread[cpu]); + wake_up(&per_cpu(siw_tx_task_g, cpu).waiting); + siw_tx_thread[cpu] = NULL; + } + } } int siw_run_sq(void *data) @@ -1221,9 +1256,6 @@ int siw_run_sq(void *data) struct siw_qp *qp; struct tx_task_t *tx_task = &per_cpu(siw_tx_task_g, nr_cpu); - init_llist_head(&tx_task->active); - init_waitqueue_head(&tx_task->waiting); - while (1) { struct llist_node *fifo_list = NULL; -- GitLab From d43ea9c3d52f2e8ab97faa0a9349b990acfa4b61 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Mon, 31 Jul 2023 09:59:15 +0800 Subject: [PATCH 0599/3445] RDMA/irdma: Fix one kernel-doc comment Remove description of @free_hwcqp in irdma_destroy_cqp(). to silence the warning: drivers/infiniband/hw/irdma/hw.c:580: warning: Excess function parameter 'free_hwcqp' description in 'irdma_destroy_cqp' Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=6028 Signed-off-by: Yang Li Link: https://lore.kernel.org/r/20230731015915.34867-1-yang.lee@linux.alibaba.com Reviewed-by: Randy Dunlap Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/irdma/hw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/infiniband/hw/irdma/hw.c b/drivers/infiniband/hw/irdma/hw.c index 8519495d23ce4..9f5d418c6e4a4 100644 --- a/drivers/infiniband/hw/irdma/hw.c +++ b/drivers/infiniband/hw/irdma/hw.c @@ -570,7 +570,6 @@ static void irdma_destroy_irq(struct irdma_pci_f *rf, /** * irdma_destroy_cqp - destroy control qp * @rf: RDMA PCI function - * @free_hwcqp: 1 if hw cqp should be freed * * Issue destroy cqp request and * free the resources associated with the cqp -- GitLab From 50f338cd8847053283c82f73129ba90c08dad06c Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Mon, 31 Jul 2023 14:55:43 +0800 Subject: [PATCH 0600/3445] RDMA/mthca: Remove unnecessary NULL assignments There are many pointers assigned first, which need not to be initialized, so remove the NULL assignments. Signed-off-by: Ruan Jinjie Link: https://lore.kernel.org/r/20230731065543.2285928-1-ruanjinjie@huawei.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/mthca/mthca_provider.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index c46df53f26cf4..e1325f2927d6e 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -53,8 +53,8 @@ static int mthca_query_device(struct ib_device *ibdev, struct ib_device_attr *props, struct ib_udata *uhw) { - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; + struct ib_smp *in_mad; + struct ib_smp *out_mad; int err = -ENOMEM; struct mthca_dev *mdev = to_mdev(ibdev); @@ -121,8 +121,8 @@ static int mthca_query_device(struct ib_device *ibdev, struct ib_device_attr *pr static int mthca_query_port(struct ib_device *ibdev, u32 port, struct ib_port_attr *props) { - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; + struct ib_smp *in_mad; + struct ib_smp *out_mad; int err = -ENOMEM; in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); @@ -217,8 +217,8 @@ out: static int mthca_query_pkey(struct ib_device *ibdev, u32 port, u16 index, u16 *pkey) { - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; + struct ib_smp *in_mad; + struct ib_smp *out_mad; int err = -ENOMEM; in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); @@ -246,8 +246,8 @@ static int mthca_query_pkey(struct ib_device *ibdev, static int mthca_query_gid(struct ib_device *ibdev, u32 port, int index, union ib_gid *gid) { - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; + struct ib_smp *in_mad; + struct ib_smp *out_mad; int err = -ENOMEM; in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); @@ -989,8 +989,8 @@ static const struct attribute_group mthca_attr_group = { static int mthca_init_node_data(struct mthca_dev *dev) { - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; + struct ib_smp *in_mad; + struct ib_smp *out_mad; int err = -ENOMEM; in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); -- GitLab From f0ff2a2dd08df50656961c26c06c7091e3792123 Mon Sep 17 00:00:00 2001 From: Shetu Ayalew Date: Sun, 23 Jul 2023 17:21:14 +0300 Subject: [PATCH 0601/3445] IB/mlx5: Add HW counter called rx_dct_connect The rx_dct_connect counter shows the number of received connection requests for the associated DCTs. Signed-off-by: Shetu Ayalew Reviewed-by: Maor Gottlieb Link: https://lore.kernel.org/r/01cd24cd7f591734741309921fdc01fc770d84a8.1690121941.git.leon@kernel.org Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/mlx5/counters.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/infiniband/hw/mlx5/counters.c b/drivers/infiniband/hw/mlx5/counters.c index 93257fa5aae8e..8300ce6228350 100644 --- a/drivers/infiniband/hw/mlx5/counters.c +++ b/drivers/infiniband/hw/mlx5/counters.c @@ -27,6 +27,7 @@ static const struct mlx5_ib_counter basic_q_cnts[] = { INIT_Q_COUNTER(rx_write_requests), INIT_Q_COUNTER(rx_read_requests), INIT_Q_COUNTER(rx_atomic_requests), + INIT_Q_COUNTER(rx_dct_connect), INIT_Q_COUNTER(out_of_buffer), }; @@ -46,6 +47,7 @@ static const struct mlx5_ib_counter vport_basic_q_cnts[] = { INIT_VPORT_Q_COUNTER(rx_write_requests), INIT_VPORT_Q_COUNTER(rx_read_requests), INIT_VPORT_Q_COUNTER(rx_atomic_requests), + INIT_VPORT_Q_COUNTER(rx_dct_connect), INIT_VPORT_Q_COUNTER(out_of_buffer), }; -- GitLab From 272bba19d631e21e47f6ffa5654d3c17c57ea2ac Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Mon, 31 Jul 2023 16:51:18 +0800 Subject: [PATCH 0602/3445] RDMA: Remove unnecessary ternary operators There are a little ternary operators, the true or false judgment of which is unnecessary in C language semantics. Signed-off-by: Ruan Jinjie Link: https://lore.kernel.org/r/20230731085118.394443-1-ruanjinjie@huawei.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/core/netlink.c | 2 +- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 5 ++--- drivers/infiniband/hw/bnxt_re/main.c | 7 +++---- drivers/infiniband/hw/bnxt_re/qplib_fp.c | 3 +-- drivers/infiniband/hw/hns/hns_roce_hem.c | 2 +- drivers/infiniband/hw/irdma/uk.c | 12 ++++++------ drivers/infiniband/hw/irdma/verbs.c | 5 ++--- drivers/infiniband/hw/ocrdma/ocrdma_verbs.c | 2 +- drivers/infiniband/hw/qedr/verbs.c | 2 +- 9 files changed, 18 insertions(+), 22 deletions(-) diff --git a/drivers/infiniband/core/netlink.c b/drivers/infiniband/core/netlink.c index 1b2cc9e45ade5..ae2db0c70788b 100644 --- a/drivers/infiniband/core/netlink.c +++ b/drivers/infiniband/core/netlink.c @@ -75,7 +75,7 @@ static bool is_nl_msg_valid(unsigned int type, unsigned int op) if (type >= RDMA_NL_NUM_CLIENTS) return false; - return (op < max_num_ops[type]) ? true : false; + return op < max_num_ops[type]; } static const struct rdma_nl_cbs * diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index 2b2505ad103d5..c46fd2a47c959 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -1336,8 +1336,7 @@ static int bnxt_re_init_qp_attr(struct bnxt_re_qp *qp, struct bnxt_re_pd *pd, qplqp->pd = &pd->qplib_pd; qplqp->qp_handle = (u64)qplqp; qplqp->max_inline_data = init_attr->cap.max_inline_data; - qplqp->sig_type = ((init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) ? - true : false); + qplqp->sig_type = init_attr->sq_sig_type == IB_SIGNAL_ALL_WR; qptype = bnxt_re_init_qp_type(rdev, init_attr); if (qptype < 0) { rc = qptype; @@ -2261,7 +2260,7 @@ static int bnxt_re_build_qp1_send_v2(struct bnxt_re_qp *qp, } is_eth = true; - is_vlan = (vlan_id && (vlan_id < 0x1000)) ? true : false; + is_vlan = vlan_id && (vlan_id < 0x1000); ib_ud_header_init(payload_size, !is_eth, is_eth, is_vlan, is_grh, ip_version, is_udp, 0, &qp->qp1_hdr); diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index 87960ac420842..d658e6798bbfd 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -433,8 +433,8 @@ int bnxt_re_hwrm_qcaps(struct bnxt_re_dev *rdev) cctx->modes.db_push = le32_to_cpu(resp.flags) & FUNC_QCAPS_RESP_FLAGS_WCB_PUSH_MODE; cctx->modes.dbr_pacing = - le32_to_cpu(resp.flags_ext2) & FUNC_QCAPS_RESP_FLAGS_EXT2_DBR_PACING_EXT_SUPPORTED ? - true : false; + le32_to_cpu(resp.flags_ext2) & + FUNC_QCAPS_RESP_FLAGS_EXT2_DBR_PACING_EXT_SUPPORTED; return 0; } @@ -1333,8 +1333,7 @@ static int bnxt_re_setup_qos(struct bnxt_re_dev *rdev) */ if ((prio_map == 0 && rdev->qplib_res.prio) || (prio_map != 0 && !rdev->qplib_res.prio)) { - rdev->qplib_res.prio = prio_map ? true : false; - + rdev->qplib_res.prio = prio_map; bnxt_re_update_gid(rdev); } diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c index 91aed77ce40d5..f9dee0d2da9c3 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c @@ -1373,8 +1373,7 @@ int bnxt_qplib_query_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) qp->state = sb->en_sqd_async_notify_state & CREQ_QUERY_QP_RESP_SB_STATE_MASK; qp->en_sqd_async_notify = sb->en_sqd_async_notify_state & - CREQ_QUERY_QP_RESP_SB_EN_SQD_ASYNC_NOTIFY ? - true : false; + CREQ_QUERY_QP_RESP_SB_EN_SQD_ASYNC_NOTIFY; qp->access = sb->access; qp->pkey_index = le16_to_cpu(sb->pkey); qp->qkey = le32_to_cpu(sb->qkey); diff --git a/drivers/infiniband/hw/hns/hns_roce_hem.c b/drivers/infiniband/hw/hns/hns_roce_hem.c index 47c0efed18211..c4ac06a338696 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hem.c +++ b/drivers/infiniband/hw/hns/hns_roce_hem.c @@ -78,7 +78,7 @@ bool hns_roce_check_whether_mhop(struct hns_roce_dev *hr_dev, u32 type) return false; } - return hop_num ? true : false; + return hop_num; } static bool hns_roce_check_hem_null(struct hns_roce_hem **hem, u64 hem_idx, diff --git a/drivers/infiniband/hw/irdma/uk.c b/drivers/infiniband/hw/irdma/uk.c index ac650a784245b..6f9238c4fe20d 100644 --- a/drivers/infiniband/hw/irdma/uk.c +++ b/drivers/infiniband/hw/irdma/uk.c @@ -282,7 +282,7 @@ int irdma_uk_rdma_write(struct irdma_qp_uk *qp, struct irdma_post_sq_info *info, bool read_fence = false; u16 quanta; - info->push_wqe = qp->push_db ? true : false; + info->push_wqe = qp->push_db; op_info = &info->op.rdma_write; if (op_info->num_lo_sges > qp->max_sq_frag_cnt) @@ -383,7 +383,7 @@ int irdma_uk_rdma_read(struct irdma_qp_uk *qp, struct irdma_post_sq_info *info, u16 quanta; u64 hdr; - info->push_wqe = qp->push_db ? true : false; + info->push_wqe = qp->push_db; op_info = &info->op.rdma_read; if (qp->max_sq_frag_cnt < op_info->num_lo_sges) @@ -468,7 +468,7 @@ int irdma_uk_send(struct irdma_qp_uk *qp, struct irdma_post_sq_info *info, bool read_fence = false; u16 quanta; - info->push_wqe = qp->push_db ? true : false; + info->push_wqe = qp->push_db; op_info = &info->op.send; if (qp->max_sq_frag_cnt < op_info->num_sges) @@ -720,7 +720,7 @@ int irdma_uk_inline_rdma_write(struct irdma_qp_uk *qp, u32 i, total_size = 0; u16 quanta; - info->push_wqe = qp->push_db ? true : false; + info->push_wqe = qp->push_db; op_info = &info->op.rdma_write; if (unlikely(qp->max_sq_frag_cnt < op_info->num_lo_sges)) @@ -794,7 +794,7 @@ int irdma_uk_inline_send(struct irdma_qp_uk *qp, u32 i, total_size = 0; u16 quanta; - info->push_wqe = qp->push_db ? true : false; + info->push_wqe = qp->push_db; op_info = &info->op.send; if (unlikely(qp->max_sq_frag_cnt < op_info->num_sges)) @@ -872,7 +872,7 @@ int irdma_uk_stag_local_invalidate(struct irdma_qp_uk *qp, bool local_fence = false; struct ib_sge sge = {}; - info->push_wqe = qp->push_db ? true : false; + info->push_wqe = qp->push_db; op_info = &info->op.inv_local_stag; local_fence = info->local_fence; diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c index b9420b0c42b33..0ca5b88d82e8e 100644 --- a/drivers/infiniband/hw/irdma/verbs.c +++ b/drivers/infiniband/hw/irdma/verbs.c @@ -1004,7 +1004,7 @@ static int irdma_create_qp(struct ib_qp *ibqp, refcount_set(&iwqp->refcnt, 1); spin_lock_init(&iwqp->lock); spin_lock_init(&iwqp->sc_qp.pfpdu.lock); - iwqp->sig_all = (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) ? 1 : 0; + iwqp->sig_all = init_attr->sq_sig_type == IB_SIGNAL_ALL_WR; rf->qp_table[qp_num] = iwqp; if (rdma_protocol_roce(&iwdev->ibdev, 1)) { @@ -3547,8 +3547,7 @@ static void irdma_process_cqe(struct ib_wc *entry, set_ib_wc_op_sq(cq_poll_info, entry); } else { set_ib_wc_op_rq(cq_poll_info, entry, - qp->qp_uk.qp_caps & IRDMA_SEND_WITH_IMM ? - true : false); + qp->qp_uk.qp_caps & IRDMA_SEND_WITH_IMM); if (qp->qp_uk.qp_type != IRDMA_QP_TYPE_ROCE_UD && cq_poll_info->stag_invalid_set) { entry->ex.invalidate_rkey = cq_poll_info->inv_stag; diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c index 58f994341e9ac..c849fdbd4c994 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c @@ -1277,7 +1277,7 @@ static void ocrdma_set_qp_init_params(struct ocrdma_qp *qp, qp->sq.max_sges = attrs->cap.max_send_sge; qp->rq.max_sges = attrs->cap.max_recv_sge; qp->state = OCRDMA_QPS_RST; - qp->signaled = (attrs->sq_sig_type == IB_SIGNAL_ALL_WR) ? true : false; + qp->signaled = attrs->sq_sig_type == IB_SIGNAL_ALL_WR; } static void ocrdma_store_gsi_qp_cq(struct ocrdma_dev *dev, diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index d745ce9dc88aa..7887a6786ed43 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -1358,7 +1358,7 @@ static void qedr_set_common_qp_params(struct qedr_dev *dev, qp->prev_wqe_size = 0; - qp->signaled = (attrs->sq_sig_type == IB_SIGNAL_ALL_WR) ? true : false; + qp->signaled = attrs->sq_sig_type == IB_SIGNAL_ALL_WR; qp->dev = dev; if (qedr_qp_has_sq(qp)) { qedr_reset_qp_hwq_info(&qp->sq); -- GitLab From a68914a53476d4fa0808219c6323eddca50e0e26 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 23 Jul 2023 19:04:43 +0900 Subject: [PATCH 0603/3445] modpost: change return type of addend_*_rel() Now that none of addend_*_rel() returns a meaningful value (the return value is always 0), change all of them to return the value of r_addend. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 63 +++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 39 deletions(-) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 8227641dd087b..a8e85b7cc0daa 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1257,21 +1257,18 @@ static void check_section_mismatch(struct module *mod, struct elf_info *elf, tosec, taddr); } -static int addend_386_rel(uint32_t *location, Elf_Rela *r) +static Elf_Addr addend_386_rel(uint32_t *location, Elf_Rela *r) { unsigned int r_typ = ELF_R_TYPE(r->r_info); switch (r_typ) { case R_386_32: - r->r_addend = TO_NATIVE(*location); - break; + return TO_NATIVE(*location); case R_386_PC32: - r->r_addend = TO_NATIVE(*location) + 4; - break; - default: - r->r_addend = (Elf_Addr)(-1); + return TO_NATIVE(*location) + 4; } - return 0; + + return (Elf_Addr)(-1); } #ifndef R_ARM_CALL @@ -1315,7 +1312,7 @@ static int32_t sign_extend32(int32_t value, int index) return (int32_t)(value << shift) >> shift; } -static int addend_arm_rel(void *loc, Elf_Sym *sym, Elf_Rela *r) +static Elf_Addr addend_arm_rel(void *loc, Elf_Sym *sym, Elf_Rela *r) { unsigned int r_typ = ELF_R_TYPE(r->r_info); uint32_t inst, upper, lower, sign, j1, j2; @@ -1325,22 +1322,19 @@ static int addend_arm_rel(void *loc, Elf_Sym *sym, Elf_Rela *r) case R_ARM_ABS32: case R_ARM_REL32: inst = TO_NATIVE(*(uint32_t *)loc); - r->r_addend = inst + sym->st_value; - break; + return inst + sym->st_value; case R_ARM_MOVW_ABS_NC: case R_ARM_MOVT_ABS: inst = TO_NATIVE(*(uint32_t *)loc); offset = sign_extend32(((inst & 0xf0000) >> 4) | (inst & 0xfff), 15); - r->r_addend = offset + sym->st_value; - break; + return offset + sym->st_value; case R_ARM_PC24: case R_ARM_CALL: case R_ARM_JUMP24: inst = TO_NATIVE(*(uint32_t *)loc); offset = sign_extend32((inst & 0x00ffffff) << 2, 25); - r->r_addend = offset + sym->st_value + 8; - break; + return offset + sym->st_value + 8; case R_ARM_THM_MOVW_ABS_NC: case R_ARM_THM_MOVT_ABS: upper = TO_NATIVE(*(uint16_t *)loc); @@ -1350,8 +1344,7 @@ static int addend_arm_rel(void *loc, Elf_Sym *sym, Elf_Rela *r) ((lower & 0x7000) >> 4) | (lower & 0x00ff), 15); - r->r_addend = offset + sym->st_value; - break; + return offset + sym->st_value; case R_ARM_THM_JUMP19: /* * Encoding T3: @@ -1372,8 +1365,7 @@ static int addend_arm_rel(void *loc, Elf_Sym *sym, Elf_Rela *r) ((upper & 0x03f) << 12) | ((lower & 0x07ff) << 1), 20); - r->r_addend = offset + sym->st_value + 4; - break; + return offset + sym->st_value + 4; case R_ARM_THM_CALL: case R_ARM_THM_JUMP24: /* @@ -1399,15 +1391,13 @@ static int addend_arm_rel(void *loc, Elf_Sym *sym, Elf_Rela *r) ((upper & 0x03ff) << 12) | ((lower & 0x07ff) << 1), 24); - r->r_addend = offset + sym->st_value + 4; - break; - default: - r->r_addend = (Elf_Addr)(-1); + return offset + sym->st_value + 4; } - return 0; + + return (Elf_Addr)(-1); } -static int addend_mips_rel(uint32_t *location, Elf_Rela *r) +static Elf_Addr addend_mips_rel(uint32_t *location, Elf_Rela *r) { unsigned int r_typ = ELF_R_TYPE(r->r_info); uint32_t inst; @@ -1415,18 +1405,13 @@ static int addend_mips_rel(uint32_t *location, Elf_Rela *r) inst = TO_NATIVE(*location); switch (r_typ) { case R_MIPS_LO16: - r->r_addend = inst & 0xffff; - break; + return inst & 0xffff; case R_MIPS_26: - r->r_addend = (inst & 0x03ffffff) << 2; - break; + return (inst & 0x03ffffff) << 2; case R_MIPS_32: - r->r_addend = inst; - break; - default: - r->r_addend = (Elf_Addr)(-1); + return inst; } - return 0; + return (Elf_Addr)(-1); } #ifndef EM_RISCV @@ -1513,6 +1498,7 @@ static void section_rel(struct module *mod, struct elf_info *elf, for (rel = start; rel < stop; rel++) { Elf_Sym *tsym; + Elf_Addr taddr = 0; void *loc; r.r_offset = TO_NATIVE(rel->r_offset); @@ -1531,27 +1517,26 @@ static void section_rel(struct module *mod, struct elf_info *elf, r.r_info = TO_NATIVE(rel->r_info); r_sym = ELF_R_SYM(r.r_info); #endif - r.r_addend = 0; loc = sym_get_data_by_offset(elf, fsecndx, r.r_offset); tsym = elf->symtab_start + r_sym; switch (elf->hdr->e_machine) { case EM_386: - addend_386_rel(loc, &r); + taddr = addend_386_rel(loc, &r); break; case EM_ARM: - addend_arm_rel(loc, tsym, &r); + taddr = addend_arm_rel(loc, tsym, &r); break; case EM_MIPS: - addend_mips_rel(loc, &r); + taddr = addend_mips_rel(loc, &r); break; default: fatal("Please add code to calculate addend for this architecture\n"); } check_section_mismatch(mod, elf, tsym, - fsecndx, fromsec, r.r_offset, r.r_addend); + fsecndx, fromsec, r.r_offset, taddr); } } -- GitLab From 71d965cf3577d68788a3d3ef044eb8e6d85013fa Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 23 Jul 2023 19:04:44 +0900 Subject: [PATCH 0604/3445] modpost: pass r_type to addend_*_rel() All of addend_*_rel() need the Elf_Rela pointer just for calculating ELF_R_TYPE(r->r_info). You can do it on the caller to de-duplicate the code. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index a8e85b7cc0daa..570a6cb6dd005 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1257,11 +1257,9 @@ static void check_section_mismatch(struct module *mod, struct elf_info *elf, tosec, taddr); } -static Elf_Addr addend_386_rel(uint32_t *location, Elf_Rela *r) +static Elf_Addr addend_386_rel(uint32_t *location, unsigned int r_type) { - unsigned int r_typ = ELF_R_TYPE(r->r_info); - - switch (r_typ) { + switch (r_type) { case R_386_32: return TO_NATIVE(*location); case R_386_PC32: @@ -1312,13 +1310,12 @@ static int32_t sign_extend32(int32_t value, int index) return (int32_t)(value << shift) >> shift; } -static Elf_Addr addend_arm_rel(void *loc, Elf_Sym *sym, Elf_Rela *r) +static Elf_Addr addend_arm_rel(void *loc, Elf_Sym *sym, unsigned int r_type) { - unsigned int r_typ = ELF_R_TYPE(r->r_info); uint32_t inst, upper, lower, sign, j1, j2; int32_t offset; - switch (r_typ) { + switch (r_type) { case R_ARM_ABS32: case R_ARM_REL32: inst = TO_NATIVE(*(uint32_t *)loc); @@ -1397,13 +1394,12 @@ static Elf_Addr addend_arm_rel(void *loc, Elf_Sym *sym, Elf_Rela *r) return (Elf_Addr)(-1); } -static Elf_Addr addend_mips_rel(uint32_t *location, Elf_Rela *r) +static Elf_Addr addend_mips_rel(uint32_t *location, unsigned int r_type) { - unsigned int r_typ = ELF_R_TYPE(r->r_info); uint32_t inst; inst = TO_NATIVE(*location); - switch (r_typ) { + switch (r_type) { case R_MIPS_LO16: return inst & 0xffff; case R_MIPS_26: @@ -1500,6 +1496,7 @@ static void section_rel(struct module *mod, struct elf_info *elf, Elf_Sym *tsym; Elf_Addr taddr = 0; void *loc; + unsigned int r_type; r.r_offset = TO_NATIVE(rel->r_offset); #if KERNEL_ELFCLASS == ELFCLASS64 @@ -1520,16 +1517,17 @@ static void section_rel(struct module *mod, struct elf_info *elf, loc = sym_get_data_by_offset(elf, fsecndx, r.r_offset); tsym = elf->symtab_start + r_sym; + r_type = ELF_R_TYPE(r.r_info); switch (elf->hdr->e_machine) { case EM_386: - taddr = addend_386_rel(loc, &r); + taddr = addend_386_rel(loc, r_type); break; case EM_ARM: - taddr = addend_arm_rel(loc, tsym, &r); + taddr = addend_arm_rel(loc, tsym, r_type); break; case EM_MIPS: - taddr = addend_mips_rel(loc, &r); + taddr = addend_mips_rel(loc, r_type); break; default: fatal("Please add code to calculate addend for this architecture\n"); -- GitLab From 4732acb75f468c12e2715cf5bf726cac873bc0e5 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 23 Jul 2023 19:04:45 +0900 Subject: [PATCH 0605/3445] modpost: clean up MIPS64 little endian relocation code MIPS64 little endian target has an odd encoding of r_info. This commit makes the special handling less ugly. It is still ugly, but #if conditionals will go away, at least. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 76 ++++++++++++++++++++++++------------------- scripts/mod/modpost.h | 22 ------------- 2 files changed, 43 insertions(+), 55 deletions(-) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 570a6cb6dd005..ca04b87c1679d 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1426,6 +1426,41 @@ static Elf_Addr addend_mips_rel(uint32_t *location, unsigned int r_type) #define R_LARCH_SUB32 55 #endif +static void get_rel_type_and_sym(struct elf_info *elf, uint64_t r_info, + unsigned int *r_type, unsigned int *r_sym) +{ + typedef struct { + Elf64_Word r_sym; /* Symbol index */ + unsigned char r_ssym; /* Special symbol for 2nd relocation */ + unsigned char r_type3; /* 3rd relocation type */ + unsigned char r_type2; /* 2nd relocation type */ + unsigned char r_type; /* 1st relocation type */ + } Elf64_Mips_R_Info; + + bool is_64bit = (elf->hdr->e_ident[EI_CLASS] == ELFCLASS64); + + if (elf->hdr->e_machine == EM_MIPS && is_64bit) { + Elf64_Mips_R_Info *mips64_r_info = (void *)&r_info; + + *r_type = mips64_r_info->r_type; + *r_sym = TO_NATIVE(mips64_r_info->r_sym); + return; + } + + if (is_64bit) { + Elf64_Xword r_info64 = r_info; + + r_info = TO_NATIVE(r_info64); + } else { + Elf32_Word r_info32 = r_info; + + r_info = TO_NATIVE(r_info32); + } + + *r_type = ELF_R_TYPE(r_info); + *r_sym = ELF_R_SYM(r_info); +} + static void section_rela(struct module *mod, struct elf_info *elf, Elf_Shdr *sechdr) { @@ -1442,32 +1477,21 @@ static void section_rela(struct module *mod, struct elf_info *elf, return; for (rela = start; rela < stop; rela++) { + unsigned int r_type; + r.r_offset = TO_NATIVE(rela->r_offset); -#if KERNEL_ELFCLASS == ELFCLASS64 - if (elf->hdr->e_machine == EM_MIPS) { - unsigned int r_typ; - r_sym = ELF64_MIPS_R_SYM(rela->r_info); - r_sym = TO_NATIVE(r_sym); - r_typ = ELF64_MIPS_R_TYPE(rela->r_info); - r.r_info = ELF64_R_INFO(r_sym, r_typ); - } else { - r.r_info = TO_NATIVE(rela->r_info); - r_sym = ELF_R_SYM(r.r_info); - } -#else - r.r_info = TO_NATIVE(rela->r_info); - r_sym = ELF_R_SYM(r.r_info); -#endif + get_rel_type_and_sym(elf, rela->r_info, &r_type, &r_sym); + r.r_addend = TO_NATIVE(rela->r_addend); switch (elf->hdr->e_machine) { case EM_RISCV: if (!strcmp("__ex_table", fromsec) && - ELF_R_TYPE(r.r_info) == R_RISCV_SUB32) + r_type == R_RISCV_SUB32) continue; break; case EM_LOONGARCH: if (!strcmp("__ex_table", fromsec) && - ELF_R_TYPE(r.r_info) == R_LARCH_SUB32) + r_type == R_LARCH_SUB32) continue; break; } @@ -1499,25 +1523,11 @@ static void section_rel(struct module *mod, struct elf_info *elf, unsigned int r_type; r.r_offset = TO_NATIVE(rel->r_offset); -#if KERNEL_ELFCLASS == ELFCLASS64 - if (elf->hdr->e_machine == EM_MIPS) { - unsigned int r_typ; - r_sym = ELF64_MIPS_R_SYM(rel->r_info); - r_sym = TO_NATIVE(r_sym); - r_typ = ELF64_MIPS_R_TYPE(rel->r_info); - r.r_info = ELF64_R_INFO(r_sym, r_typ); - } else { - r.r_info = TO_NATIVE(rel->r_info); - r_sym = ELF_R_SYM(r.r_info); - } -#else - r.r_info = TO_NATIVE(rel->r_info); - r_sym = ELF_R_SYM(r.r_info); -#endif + + get_rel_type_and_sym(elf, rel->r_info, &r_type, &r_sym); loc = sym_get_data_by_offset(elf, fsecndx, r.r_offset); tsym = elf->symtab_start + r_sym; - r_type = ELF_R_TYPE(r.r_info); switch (elf->hdr->e_machine) { case EM_386: diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index dfdb9484e3255..5f94c2c9f2d95 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -50,28 +50,6 @@ #define ELF_R_TYPE ELF64_R_TYPE #endif -/* The 64-bit MIPS ELF ABI uses an unusual reloc format. */ -typedef struct -{ - Elf32_Word r_sym; /* Symbol index */ - unsigned char r_ssym; /* Special symbol for 2nd relocation */ - unsigned char r_type3; /* 3rd relocation type */ - unsigned char r_type2; /* 2nd relocation type */ - unsigned char r_type1; /* 1st relocation type */ -} _Elf64_Mips_R_Info; - -typedef union -{ - Elf64_Xword r_info_number; - _Elf64_Mips_R_Info r_info_fields; -} _Elf64_Mips_R_Info_union; - -#define ELF64_MIPS_R_SYM(i) \ - ((__extension__ (_Elf64_Mips_R_Info_union)(i)).r_info_fields.r_sym) - -#define ELF64_MIPS_R_TYPE(i) \ - ((__extension__ (_Elf64_Mips_R_Info_union)(i)).r_info_fields.r_type1) - #if KERNEL_ELFDATA != HOST_ELFDATA static inline void __endian(const void *src, void *dest, unsigned int size) -- GitLab From 77f39e9344a151f2c055ce85875c3c57c6cfdfa3 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 23 Jul 2023 19:04:46 +0900 Subject: [PATCH 0606/3445] modpost: remove ElF_Rela variables from for-loop in section_rel(a) Remove the Elf_Rela variables used in the for-loop in section_rel(). This makes the code consistent; section_rel() only uses Elf_Rel, section_rela() only uses Elf_Rela. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index ca04b87c1679d..9761f9d0eec03 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1465,8 +1465,6 @@ static void section_rela(struct module *mod, struct elf_info *elf, Elf_Shdr *sechdr) { Elf_Rela *rela; - Elf_Rela r; - unsigned int r_sym; unsigned int fsecndx = sechdr->sh_info; const char *fromsec = sec_name(elf, fsecndx); Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset; @@ -1477,12 +1475,14 @@ static void section_rela(struct module *mod, struct elf_info *elf, return; for (rela = start; rela < stop; rela++) { - unsigned int r_type; + Elf_Addr taddr, r_offset; + unsigned int r_type, r_sym; - r.r_offset = TO_NATIVE(rela->r_offset); + r_offset = TO_NATIVE(rela->r_offset); get_rel_type_and_sym(elf, rela->r_info, &r_type, &r_sym); - r.r_addend = TO_NATIVE(rela->r_addend); + taddr = TO_NATIVE(rela->r_addend); + switch (elf->hdr->e_machine) { case EM_RISCV: if (!strcmp("__ex_table", fromsec) && @@ -1497,7 +1497,7 @@ static void section_rela(struct module *mod, struct elf_info *elf, } check_section_mismatch(mod, elf, elf->symtab_start + r_sym, - fsecndx, fromsec, r.r_offset, r.r_addend); + fsecndx, fromsec, r_offset, taddr); } } @@ -1505,8 +1505,6 @@ static void section_rel(struct module *mod, struct elf_info *elf, Elf_Shdr *sechdr) { Elf_Rel *rel; - Elf_Rela r; - unsigned int r_sym; unsigned int fsecndx = sechdr->sh_info; const char *fromsec = sec_name(elf, fsecndx); Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset; @@ -1518,15 +1516,14 @@ static void section_rel(struct module *mod, struct elf_info *elf, for (rel = start; rel < stop; rel++) { Elf_Sym *tsym; - Elf_Addr taddr = 0; + Elf_Addr taddr = 0, r_offset; + unsigned int r_type, r_sym; void *loc; - unsigned int r_type; - - r.r_offset = TO_NATIVE(rel->r_offset); + r_offset = TO_NATIVE(rel->r_offset); get_rel_type_and_sym(elf, rel->r_info, &r_type, &r_sym); - loc = sym_get_data_by_offset(elf, fsecndx, r.r_offset); + loc = sym_get_data_by_offset(elf, fsecndx, r_offset); tsym = elf->symtab_start + r_sym; switch (elf->hdr->e_machine) { @@ -1544,7 +1541,7 @@ static void section_rel(struct module *mod, struct elf_info *elf, } check_section_mismatch(mod, elf, tsym, - fsecndx, fromsec, r.r_offset, taddr); + fsecndx, fromsec, r_offset, taddr); } } -- GitLab From ec6c7c9f5fc4e260725cb45061b54956d85f4c86 Mon Sep 17 00:00:00 2001 From: Wang Jinchao Date: Tue, 11 Jul 2023 16:47:30 +0800 Subject: [PATCH 0607/3445] scsi: aic7xxx: Fix firmware build fatal error When building with CONFIG_AIC7XXX_BUILD_FIRMWARE=y, two fatal errors are reported as shown below: aicasm_gram.tab.c:203:10: fatal error: aicasm_gram.tab.h: No such file or directory aicasm_macro_gram.tab.c:167:10: fatal error: aicasm_macro_gram.tab.h: No such file or directory Fix these issues to make randconfig builds more reliable. [mkp: add missing include] Signed-off-by: Wang Jinchao Link: https://lore.kernel.org/r/ZK0XIj6XzY5MCvtd@fedora Signed-off-by: Martin K. Petersen --- drivers/scsi/aic7xxx/aicasm/Makefile | 18 +++--------------- drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c | 1 + 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/aic7xxx/aicasm/Makefile b/drivers/scsi/aic7xxx/aicasm/Makefile index 243adb0a38d13..a3f2357a3f08b 100644 --- a/drivers/scsi/aic7xxx/aicasm/Makefile +++ b/drivers/scsi/aic7xxx/aicasm/Makefile @@ -61,23 +61,11 @@ $(OUTDIR)/aicdb.h: clean: rm -f $(clean-files) -# Create a dependency chain in generated files -# to avoid concurrent invocations of the single -# rule that builds them all. -$(OUTDIR)/aicasm_gram.c: $(OUTDIR)/aicasm_gram.h $(OUTDIR)/aicasm_gram.c $(OUTDIR)/aicasm_gram.h: aicasm_gram.y - $(YACC) $(YFLAGS) -b $(<:.y=) $< - mv $(<:.y=).tab.c $(OUTDIR)/$(<:.y=.c) - mv $(<:.y=).tab.h $(OUTDIR)/$(<:.y=.h) - -# Create a dependency chain in generated files -# to avoid concurrent invocations of the single -# rule that builds them all. -$(OUTDIR)/aicasm_macro_gram.c: $(OUTDIR)/aicasm_macro_gram.h + $(YACC) $(YFLAGS) -b $(<:.y=) $< -o $(OUTDIR)/$(<:.y=.c) + $(OUTDIR)/aicasm_macro_gram.c $(OUTDIR)/aicasm_macro_gram.h: aicasm_macro_gram.y - $(YACC) $(YFLAGS) -b $(<:.y=) -p mm $< - mv $(<:.y=).tab.c $(OUTDIR)/$(<:.y=.c) - mv $(<:.y=).tab.h $(OUTDIR)/$(<:.y=.h) + $(YACC) $(YFLAGS) -b $(<:.y=) -p mm $< -o $(OUTDIR)/$(<:.y=.c) $(OUTDIR)/aicasm_scan.c: aicasm_scan.l $(LEX) $(LFLAGS) -o $@ $< diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c index 975fcfcc0d8f6..2b44eb5702eb7 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c @@ -52,6 +52,7 @@ #include #include #include +#include #include "aicasm_symbol.h" #include "aicasm.h" -- GitLab From 27152bceea1df27ffebb12ac9cd9adbf2c4c3f35 Mon Sep 17 00:00:00 2001 From: Ajay Kaher Date: Fri, 28 Jul 2023 23:50:51 +0530 Subject: [PATCH 0608/3445] eventfs: Move tracing/events to eventfs Up until now, /sys/kernel/tracing/events was no different than any other part of tracefs. The files and directories within the events directory was created when the tracefs was mounted, and also created for the instances in /sys/kernel/tracing/instances//events. Most of these files and directories will never be referenced. Since there are thousands of these files and directories they spend their time wasting precious memory resources. Move the "events" directory to the new eventfs. The eventfs will take the meta data of the events that they represent and store that. When the files in the events directory are referenced, the dentry and inodes to represent them are then created. When the files are no longer referenced, they are freed. This saves the precious memory resources that were wasted on these seldom referenced dentries and inodes. Running the following: ~# cat /proc/meminfo /proc/slabinfo > before.out ~# mkdir /sys/kernel/tracing/instances/foo ~# cat /proc/meminfo /proc/slabinfo > after.out to test the changes produces the following deltas: Before this change: Before after deltas for meminfo: MemFree: -32260 MemAvailable: -21496 KReclaimable: 21528 Slab: 22440 SReclaimable: 21528 SUnreclaim: 912 VmallocUsed: 16 Before after deltas for slabinfo: : [ * = ] tracefs_inode_cache: 14472 [* 1184 = 17134848] buffer_head: 24 [* 168 = 4032] hmem_inode_cache: 28 [* 1480 = 41440] dentry: 14450 [* 312 = 4508400] lsm_inode_cache: 14453 [* 32 = 462496] vma_lock: 11 [* 152 = 1672] vm_area_struct: 2 [* 184 = 368] trace_event_file: 1748 [* 88 = 153824] kmalloc-256: 1072 [* 256 = 274432] kmalloc-64: 2842 [* 64 = 181888] Total slab additions in size: 22,763,400 bytes With this change: Before after deltas for meminfo: MemFree: -12600 MemAvailable: -12580 Cached: 24 Active: 12 Inactive: 68 Inactive(anon): 48 Active(file): 12 Inactive(file): 20 Dirty: -4 AnonPages: 68 KReclaimable: 12 Slab: 1856 SReclaimable: 12 SUnreclaim: 1844 KernelStack: 16 PageTables: 36 VmallocUsed: 16 Before after deltas for slabinfo: : [ * = ] tracefs_inode_cache: 108 [* 1184 = 127872] buffer_head: 24 [* 168 = 4032] hmem_inode_cache: 18 [* 1480 = 26640] dentry: 127 [* 312 = 39624] lsm_inode_cache: 152 [* 32 = 4864] vma_lock: 67 [* 152 = 10184] vm_area_struct: -12 [* 184 = -2208] trace_event_file: 1764 [* 96 = 169344] kmalloc-96: 14322 [* 96 = 1374912] kmalloc-64: 2814 [* 64 = 180096] kmalloc-32: 1103 [* 32 = 35296] kmalloc-16: 2308 [* 16 = 36928] kmalloc-8: 12800 [* 8 = 102400] Total slab additions in size: 2,109,984 bytes Which is a savings of 20,653,416 bytes (20 MB) per tracing instance. Link: https://lkml.kernel.org/r/1690568452-46553-10-git-send-email-akaher@vmware.com Signed-off-by: Ajay Kaher Co-developed-by: Steven Rostedt (VMware) Signed-off-by: Steven Rostedt (VMware) Tested-by: Ching-lin Yu Signed-off-by: Steven Rostedt (Google) --- fs/tracefs/inode.c | 18 ++++++++++ include/linux/trace_events.h | 1 + kernel/trace/trace.h | 2 +- kernel/trace/trace_events.c | 65 ++++++++++++++++++------------------ 4 files changed, 53 insertions(+), 33 deletions(-) diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c index d9273066f25f5..bb6de89eb4461 100644 --- a/fs/tracefs/inode.c +++ b/fs/tracefs/inode.c @@ -374,6 +374,23 @@ static const struct super_operations tracefs_super_operations = { .show_options = tracefs_show_options, }; +static void tracefs_dentry_iput(struct dentry *dentry, struct inode *inode) +{ + struct tracefs_inode *ti; + + if (!dentry || !inode) + return; + + ti = get_tracefs(inode); + if (ti && ti->flags & TRACEFS_EVENT_INODE) + eventfs_set_ef_status_free(dentry); + iput(inode); +} + +static const struct dentry_operations tracefs_dentry_operations = { + .d_iput = tracefs_dentry_iput, +}; + static int trace_fill_super(struct super_block *sb, void *data, int silent) { static const struct tree_descr trace_files[] = {{""}}; @@ -396,6 +413,7 @@ static int trace_fill_super(struct super_block *sb, void *data, int silent) goto fail; sb->s_op = &tracefs_super_operations; + sb->s_d_op = &tracefs_dentry_operations; tracefs_apply_options(sb, false); diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h index 3930e676436c9..c17623c780298 100644 --- a/include/linux/trace_events.h +++ b/include/linux/trace_events.h @@ -638,6 +638,7 @@ struct trace_event_file { struct list_head list; struct trace_event_call *event_call; struct event_filter __rcu *filter; + struct eventfs_file *ef; struct dentry *dir; struct trace_array *tr; struct trace_subsystem_dir *system; diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index ba7ababb8308b..5b1f9e24764a1 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -1334,7 +1334,7 @@ struct trace_subsystem_dir { struct list_head list; struct event_subsystem *subsystem; struct trace_array *tr; - struct dentry *entry; + struct eventfs_file *ef; int ref_count; int nr_events; }; diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 3ecc41f6acd96..ed367d713be07 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -984,7 +984,7 @@ static void remove_subsystem(struct trace_subsystem_dir *dir) return; if (!--dir->nr_events) { - tracefs_remove(dir->entry); + eventfs_remove(dir->ef); list_del(&dir->list); __put_system_dir(dir); } @@ -1005,7 +1005,7 @@ static void remove_event_file_dir(struct trace_event_file *file) tracefs_remove(dir); } - + eventfs_remove(file->ef); list_del(&file->list); remove_subsystem(file->system); free_event_filter(file->filter); @@ -2291,13 +2291,13 @@ create_new_subsystem(const char *name) return NULL; } -static struct dentry * +static struct eventfs_file * event_subsystem_dir(struct trace_array *tr, const char *name, struct trace_event_file *file, struct dentry *parent) { struct event_subsystem *system, *iter; struct trace_subsystem_dir *dir; - struct dentry *entry; + int res; /* First see if we did not already create this dir */ list_for_each_entry(dir, &tr->systems, list) { @@ -2305,7 +2305,7 @@ event_subsystem_dir(struct trace_array *tr, const char *name, if (strcmp(system->name, name) == 0) { dir->nr_events++; file->system = dir; - return dir->entry; + return dir->ef; } } @@ -2329,8 +2329,8 @@ event_subsystem_dir(struct trace_array *tr, const char *name, } else __get_system(system); - dir->entry = tracefs_create_dir(name, parent); - if (!dir->entry) { + dir->ef = eventfs_add_subsystem_dir(name, parent); + if (IS_ERR(dir->ef)) { pr_warn("Failed to create system directory %s\n", name); __put_system(system); goto out_free; @@ -2345,22 +2345,22 @@ event_subsystem_dir(struct trace_array *tr, const char *name, /* the ftrace system is special, do not create enable or filter files */ if (strcmp(name, "ftrace") != 0) { - entry = tracefs_create_file("filter", TRACE_MODE_WRITE, - dir->entry, dir, + res = eventfs_add_file("filter", TRACE_MODE_WRITE, + dir->ef, dir, &ftrace_subsystem_filter_fops); - if (!entry) { + if (res) { kfree(system->filter); system->filter = NULL; pr_warn("Could not create tracefs '%s/filter' entry\n", name); } - trace_create_file("enable", TRACE_MODE_WRITE, dir->entry, dir, + eventfs_add_file("enable", TRACE_MODE_WRITE, dir->ef, dir, &ftrace_system_enable_fops); } list_add(&dir->list, &tr->systems); - return dir->entry; + return dir->ef; out_free: kfree(dir); @@ -2413,8 +2413,8 @@ static int event_create_dir(struct dentry *parent, struct trace_event_file *file) { struct trace_event_call *call = file->event_call; + struct eventfs_file *ef_subsystem = NULL; struct trace_array *tr = file->tr; - struct dentry *d_events; const char *name; int ret; @@ -2426,24 +2426,24 @@ event_create_dir(struct dentry *parent, struct trace_event_file *file) if (WARN_ON_ONCE(strcmp(call->class->system, TRACE_SYSTEM) == 0)) return -ENODEV; - d_events = event_subsystem_dir(tr, call->class->system, file, parent); - if (!d_events) + ef_subsystem = event_subsystem_dir(tr, call->class->system, file, parent); + if (!ef_subsystem) return -ENOMEM; name = trace_event_name(call); - file->dir = tracefs_create_dir(name, d_events); - if (!file->dir) { + file->ef = eventfs_add_dir(name, ef_subsystem); + if (IS_ERR(file->ef)) { pr_warn("Could not create tracefs '%s' directory\n", name); return -1; } if (call->class->reg && !(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)) - trace_create_file("enable", TRACE_MODE_WRITE, file->dir, file, + eventfs_add_file("enable", TRACE_MODE_WRITE, file->ef, file, &ftrace_enable_fops); #ifdef CONFIG_PERF_EVENTS if (call->event.type && call->class->reg) - trace_create_file("id", TRACE_MODE_READ, file->dir, + eventfs_add_file("id", TRACE_MODE_READ, file->ef, (void *)(long)call->event.type, &ftrace_event_id_fops); #endif @@ -2459,27 +2459,27 @@ event_create_dir(struct dentry *parent, struct trace_event_file *file) * triggers or filters. */ if (!(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)) { - trace_create_file("filter", TRACE_MODE_WRITE, file->dir, + eventfs_add_file("filter", TRACE_MODE_WRITE, file->ef, file, &ftrace_event_filter_fops); - trace_create_file("trigger", TRACE_MODE_WRITE, file->dir, + eventfs_add_file("trigger", TRACE_MODE_WRITE, file->ef, file, &event_trigger_fops); } #ifdef CONFIG_HIST_TRIGGERS - trace_create_file("hist", TRACE_MODE_READ, file->dir, file, + eventfs_add_file("hist", TRACE_MODE_READ, file->ef, file, &event_hist_fops); #endif #ifdef CONFIG_HIST_TRIGGERS_DEBUG - trace_create_file("hist_debug", TRACE_MODE_READ, file->dir, file, + eventfs_add_file("hist_debug", TRACE_MODE_READ, file->ef, file, &event_hist_debug_fops); #endif - trace_create_file("format", TRACE_MODE_READ, file->dir, call, + eventfs_add_file("format", TRACE_MODE_READ, file->ef, call, &ftrace_event_format_fops); #ifdef CONFIG_TRACE_EVENT_INJECT if (call->event.type && call->class->reg) - trace_create_file("inject", 0200, file->dir, file, + eventfs_add_file("inject", 0200, file->ef, file, &event_inject_fops); #endif @@ -3632,21 +3632,22 @@ create_event_toplevel_files(struct dentry *parent, struct trace_array *tr) { struct dentry *d_events; struct dentry *entry; + int error = 0; entry = trace_create_file("set_event", TRACE_MODE_WRITE, parent, tr, &ftrace_set_event_fops); if (!entry) return -ENOMEM; - d_events = tracefs_create_dir("events", parent); - if (!d_events) { + d_events = eventfs_create_events_dir("events", parent); + if (IS_ERR(d_events)) { pr_warn("Could not create tracefs 'events' directory\n"); return -ENOMEM; } - entry = trace_create_file("enable", TRACE_MODE_WRITE, d_events, + error = eventfs_add_events_file("enable", TRACE_MODE_WRITE, d_events, tr, &ftrace_tr_enable_fops); - if (!entry) + if (error) return -ENOMEM; /* There are not as crucial, just warn if they are not created */ @@ -3659,11 +3660,11 @@ create_event_toplevel_files(struct dentry *parent, struct trace_array *tr) &ftrace_set_event_notrace_pid_fops); /* ring buffer internal formats */ - trace_create_file("header_page", TRACE_MODE_READ, d_events, + eventfs_add_events_file("header_page", TRACE_MODE_READ, d_events, ring_buffer_print_page_header, &ftrace_show_header_fops); - trace_create_file("header_event", TRACE_MODE_READ, d_events, + eventfs_add_events_file("header_event", TRACE_MODE_READ, d_events, ring_buffer_print_entry_header, &ftrace_show_header_fops); @@ -3751,7 +3752,7 @@ int event_trace_del_tracer(struct trace_array *tr) down_write(&trace_event_sem); __trace_remove_event_dirs(tr); - tracefs_remove(tr->event_dir); + eventfs_remove_events_dir(tr->event_dir); up_write(&trace_event_sem); tr->event_dir = NULL; -- GitLab From 801f287c93ff95582b0a2d2163f12870a2f076d4 Mon Sep 17 00:00:00 2001 From: Konstantin Shelekhin Date: Sat, 22 Jul 2023 18:26:37 +0300 Subject: [PATCH 0609/3445] scsi: target: iscsi: Fix buffer overflow in lio_target_nacl_info_show() The function lio_target_nacl_info_show() uses sprintf() in a loop to print details for every iSCSI connection in a session without checking for the buffer length. With enough iSCSI connections it's possible to overflow the buffer provided by configfs and corrupt the memory. This patch replaces sprintf() with sysfs_emit_at() that checks for buffer boundries. Signed-off-by: Konstantin Shelekhin Link: https://lore.kernel.org/r/20230722152657.168859-2-k.shelekhin@yadro.com Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_configfs.c | 54 ++++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 5d0f51822414e..c142a67dc7cc2 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -533,102 +533,102 @@ static ssize_t lio_target_nacl_info_show(struct config_item *item, char *page) spin_lock_bh(&se_nacl->nacl_sess_lock); se_sess = se_nacl->nacl_sess; if (!se_sess) { - rb += sprintf(page+rb, "No active iSCSI Session for Initiator" + rb += sysfs_emit_at(page, rb, "No active iSCSI Session for Initiator" " Endpoint: %s\n", se_nacl->initiatorname); } else { sess = se_sess->fabric_sess_ptr; - rb += sprintf(page+rb, "InitiatorName: %s\n", + rb += sysfs_emit_at(page, rb, "InitiatorName: %s\n", sess->sess_ops->InitiatorName); - rb += sprintf(page+rb, "InitiatorAlias: %s\n", + rb += sysfs_emit_at(page, rb, "InitiatorAlias: %s\n", sess->sess_ops->InitiatorAlias); - rb += sprintf(page+rb, + rb += sysfs_emit_at(page, rb, "LIO Session ID: %u ISID: 0x%6ph TSIH: %hu ", sess->sid, sess->isid, sess->tsih); - rb += sprintf(page+rb, "SessionType: %s\n", + rb += sysfs_emit_at(page, rb, "SessionType: %s\n", (sess->sess_ops->SessionType) ? "Discovery" : "Normal"); - rb += sprintf(page+rb, "Session State: "); + rb += sysfs_emit_at(page, rb, "Session State: "); switch (sess->session_state) { case TARG_SESS_STATE_FREE: - rb += sprintf(page+rb, "TARG_SESS_FREE\n"); + rb += sysfs_emit_at(page, rb, "TARG_SESS_FREE\n"); break; case TARG_SESS_STATE_ACTIVE: - rb += sprintf(page+rb, "TARG_SESS_STATE_ACTIVE\n"); + rb += sysfs_emit_at(page, rb, "TARG_SESS_STATE_ACTIVE\n"); break; case TARG_SESS_STATE_LOGGED_IN: - rb += sprintf(page+rb, "TARG_SESS_STATE_LOGGED_IN\n"); + rb += sysfs_emit_at(page, rb, "TARG_SESS_STATE_LOGGED_IN\n"); break; case TARG_SESS_STATE_FAILED: - rb += sprintf(page+rb, "TARG_SESS_STATE_FAILED\n"); + rb += sysfs_emit_at(page, rb, "TARG_SESS_STATE_FAILED\n"); break; case TARG_SESS_STATE_IN_CONTINUE: - rb += sprintf(page+rb, "TARG_SESS_STATE_IN_CONTINUE\n"); + rb += sysfs_emit_at(page, rb, "TARG_SESS_STATE_IN_CONTINUE\n"); break; default: - rb += sprintf(page+rb, "ERROR: Unknown Session" + rb += sysfs_emit_at(page, rb, "ERROR: Unknown Session" " State!\n"); break; } - rb += sprintf(page+rb, "---------------------[iSCSI Session" + rb += sysfs_emit_at(page, rb, "---------------------[iSCSI Session" " Values]-----------------------\n"); - rb += sprintf(page+rb, " CmdSN/WR : CmdSN/WC : ExpCmdSN" + rb += sysfs_emit_at(page, rb, " CmdSN/WR : CmdSN/WC : ExpCmdSN" " : MaxCmdSN : ITT : TTT\n"); max_cmd_sn = (u32) atomic_read(&sess->max_cmd_sn); - rb += sprintf(page+rb, " 0x%08x 0x%08x 0x%08x 0x%08x" + rb += sysfs_emit_at(page, rb, " 0x%08x 0x%08x 0x%08x 0x%08x" " 0x%08x 0x%08x\n", sess->cmdsn_window, (max_cmd_sn - sess->exp_cmd_sn) + 1, sess->exp_cmd_sn, max_cmd_sn, sess->init_task_tag, sess->targ_xfer_tag); - rb += sprintf(page+rb, "----------------------[iSCSI" + rb += sysfs_emit_at(page, rb, "----------------------[iSCSI" " Connections]-------------------------\n"); spin_lock(&sess->conn_lock); list_for_each_entry(conn, &sess->sess_conn_list, conn_list) { - rb += sprintf(page+rb, "CID: %hu Connection" + rb += sysfs_emit_at(page, rb, "CID: %hu Connection" " State: ", conn->cid); switch (conn->conn_state) { case TARG_CONN_STATE_FREE: - rb += sprintf(page+rb, + rb += sysfs_emit_at(page, rb, "TARG_CONN_STATE_FREE\n"); break; case TARG_CONN_STATE_XPT_UP: - rb += sprintf(page+rb, + rb += sysfs_emit_at(page, rb, "TARG_CONN_STATE_XPT_UP\n"); break; case TARG_CONN_STATE_IN_LOGIN: - rb += sprintf(page+rb, + rb += sysfs_emit_at(page, rb, "TARG_CONN_STATE_IN_LOGIN\n"); break; case TARG_CONN_STATE_LOGGED_IN: - rb += sprintf(page+rb, + rb += sysfs_emit_at(page, rb, "TARG_CONN_STATE_LOGGED_IN\n"); break; case TARG_CONN_STATE_IN_LOGOUT: - rb += sprintf(page+rb, + rb += sysfs_emit_at(page, rb, "TARG_CONN_STATE_IN_LOGOUT\n"); break; case TARG_CONN_STATE_LOGOUT_REQUESTED: - rb += sprintf(page+rb, + rb += sysfs_emit_at(page, rb, "TARG_CONN_STATE_LOGOUT_REQUESTED\n"); break; case TARG_CONN_STATE_CLEANUP_WAIT: - rb += sprintf(page+rb, + rb += sysfs_emit_at(page, rb, "TARG_CONN_STATE_CLEANUP_WAIT\n"); break; default: - rb += sprintf(page+rb, + rb += sysfs_emit_at(page, rb, "ERROR: Unknown Connection State!\n"); break; } - rb += sprintf(page+rb, " Address %pISc %s", &conn->login_sockaddr, + rb += sysfs_emit_at(page, rb, " Address %pISc %s", &conn->login_sockaddr, (conn->network_transport == ISCSI_TCP) ? "TCP" : "SCTP"); - rb += sprintf(page+rb, " StatSN: 0x%08x\n", + rb += sysfs_emit_at(page, rb, " StatSN: 0x%08x\n", conn->stat_sn); } spin_unlock(&sess->conn_lock); -- GitLab From c0431feb0a75e24afe60a8090c9f93dd9e33fd81 Mon Sep 17 00:00:00 2001 From: Konstantin Shelekhin Date: Sat, 22 Jul 2023 18:26:38 +0300 Subject: [PATCH 0610/3445] scsi: target: iscsi: Stop using sprintf() in iscsi_target_configfs.c Get rid of sprintf() in favor of sysfs_emit(). The latter ensures not to overflow the given buffer. Signed-off-by: Konstantin Shelekhin Link: https://lore.kernel.org/r/20230722152657.168859-3-k.shelekhin@yadro.com Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_configfs.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index c142a67dc7cc2..098eae55c4c52 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -45,9 +45,9 @@ static ssize_t lio_target_np_driver_show(struct config_item *item, char *page, tpg_np_new = iscsit_tpg_locate_child_np(tpg_np, type); if (tpg_np_new) - rb = sprintf(page, "1\n"); + rb = sysfs_emit(page, "1\n"); else - rb = sprintf(page, "0\n"); + rb = sysfs_emit(page, "0\n"); return rb; } @@ -282,7 +282,7 @@ static ssize_t iscsi_nacl_attrib_##name##_show(struct config_item *item,\ { \ struct se_node_acl *se_nacl = attrib_to_nacl(item); \ struct iscsi_node_acl *nacl = to_iscsi_nacl(se_nacl); \ - return sprintf(page, "%u\n", nacl->node_attrib.name); \ + return sysfs_emit(page, "%u\n", nacl->node_attrib.name); \ } \ \ static ssize_t iscsi_nacl_attrib_##name##_store(struct config_item *item,\ @@ -320,7 +320,7 @@ static ssize_t iscsi_nacl_attrib_authentication_show(struct config_item *item, struct se_node_acl *se_nacl = attrib_to_nacl(item); struct iscsi_node_acl *nacl = to_iscsi_nacl(se_nacl); - return sprintf(page, "%d\n", nacl->node_attrib.authentication); + return sysfs_emit(page, "%d\n", nacl->node_attrib.authentication); } static ssize_t iscsi_nacl_attrib_authentication_store(struct config_item *item, @@ -641,7 +641,7 @@ static ssize_t lio_target_nacl_info_show(struct config_item *item, char *page) static ssize_t lio_target_nacl_cmdsn_depth_show(struct config_item *item, char *page) { - return sprintf(page, "%u\n", acl_to_nacl(item)->queue_depth); + return sysfs_emit(page, "%u\n", acl_to_nacl(item)->queue_depth); } static ssize_t lio_target_nacl_cmdsn_depth_store(struct config_item *item, @@ -750,7 +750,7 @@ static ssize_t iscsi_tpg_attrib_##name##_show(struct config_item *item, \ if (iscsit_get_tpg(tpg) < 0) \ return -EINVAL; \ \ - rb = sprintf(page, "%u\n", tpg->tpg_attrib.name); \ + rb = sysfs_emit(page, "%u\n", tpg->tpg_attrib.name); \ iscsit_put_tpg(tpg); \ return rb; \ } \ @@ -1138,7 +1138,7 @@ static void lio_target_tiqn_deltpg(struct se_portal_group *se_tpg) static ssize_t lio_target_wwn_lio_version_show(struct config_item *item, char *page) { - return sprintf(page, "Datera Inc. iSCSI Target "ISCSIT_VERSION"\n"); + return sysfs_emit(page, "Datera Inc. iSCSI Target %s\n", ISCSIT_VERSION); } CONFIGFS_ATTR_RO(lio_target_wwn_, lio_version); @@ -1146,7 +1146,7 @@ CONFIGFS_ATTR_RO(lio_target_wwn_, lio_version); static ssize_t lio_target_wwn_cpus_allowed_list_show( struct config_item *item, char *page) { - return sprintf(page, "%*pbl\n", + return sysfs_emit(page, "%*pbl\n", cpumask_pr_args(iscsit_global->allowed_cpumask)); } @@ -1283,7 +1283,7 @@ static ssize_t iscsi_disc_enforce_discovery_auth_show(struct config_item *item, { struct iscsi_node_auth *discovery_auth = &iscsit_global->discovery_acl.node_auth; - return sprintf(page, "%d\n", discovery_auth->enforce_discovery_auth); + return sysfs_emit(page, "%d\n", discovery_auth->enforce_discovery_auth); } static ssize_t iscsi_disc_enforce_discovery_auth_store(struct config_item *item, -- GitLab From 7c1130ea5cae215588e6d51242b877fd405e6c32 Mon Sep 17 00:00:00 2001 From: Ajay Kaher Date: Fri, 28 Jul 2023 23:50:52 +0530 Subject: [PATCH 0611/3445] test: ftrace: Fix kprobe test for eventfs kprobe_args_char.tc, kprobe_args_string.tc has validation check for tracefs_create_dir, for eventfs it should be eventfs_create_dir. Link: https://lkml.kernel.org/r/1690568452-46553-11-git-send-email-akaher@vmware.com Signed-off-by: Ajay Kaher Co-developed-by: Steven Rostedt (VMware) Signed-off-by: Steven Rostedt (VMware) Tested-by: Ching-lin Yu Acked-by: Masami Hiramatsu (Google) Signed-off-by: Steven Rostedt (Google) --- .../selftests/ftrace/test.d/kprobe/kprobe_args_char.tc | 9 +++++++-- .../selftests/ftrace/test.d/kprobe/kprobe_args_string.tc | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_char.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_char.tc index 285b4770efad4..ff7499eb98d6d 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_char.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_char.tc @@ -34,14 +34,19 @@ mips*) esac : "Test get argument (1)" -echo "p:testprobe tracefs_create_dir arg1=+0(${ARG1}):char" > kprobe_events +if grep -q eventfs_add_dir available_filter_functions; then + DIR_NAME="eventfs_add_dir" +else + DIR_NAME="tracefs_create_dir" +fi +echo "p:testprobe ${DIR_NAME} arg1=+0(${ARG1}):char" > kprobe_events echo 1 > events/kprobes/testprobe/enable echo "p:test $FUNCTION_FORK" >> kprobe_events grep -qe "testprobe.* arg1='t'" trace echo 0 > events/kprobes/testprobe/enable : "Test get argument (2)" -echo "p:testprobe tracefs_create_dir arg1=+0(${ARG1}):char arg2=+0(${ARG1}):char[4]" > kprobe_events +echo "p:testprobe ${DIR_NAME} arg1=+0(${ARG1}):char arg2=+0(${ARG1}):char[4]" > kprobe_events echo 1 > events/kprobes/testprobe/enable echo "p:test $FUNCTION_FORK" >> kprobe_events grep -qe "testprobe.* arg1='t' arg2={'t','e','s','t'}" trace diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc index a4f8e7c53c1f7..a202b2ea4baf9 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc @@ -37,14 +37,19 @@ loongarch*) esac : "Test get argument (1)" -echo "p:testprobe tracefs_create_dir arg1=+0(${ARG1}):string" > kprobe_events +if grep -q eventfs_add_dir available_filter_functions; then + DIR_NAME="eventfs_add_dir" +else + DIR_NAME="tracefs_create_dir" +fi +echo "p:testprobe ${DIR_NAME} arg1=+0(${ARG1}):string" > kprobe_events echo 1 > events/kprobes/testprobe/enable echo "p:test $FUNCTION_FORK" >> kprobe_events grep -qe "testprobe.* arg1=\"test\"" trace echo 0 > events/kprobes/testprobe/enable : "Test get argument (2)" -echo "p:testprobe tracefs_create_dir arg1=+0(${ARG1}):string arg2=+0(${ARG1}):string" > kprobe_events +echo "p:testprobe ${DIR_NAME} arg1=+0(${ARG1}):string arg2=+0(${ARG1}):string" > kprobe_events echo 1 > events/kprobes/testprobe/enable echo "p:test $FUNCTION_FORK" >> kprobe_events grep -qe "testprobe.* arg1=\"test\" arg2=\"test\"" trace -- GitLab From b7fc2caf20eadae28b182e446404b63ed8d8cf23 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Wed, 26 Jul 2023 10:47:59 +0530 Subject: [PATCH 0612/3445] scsi: hisi_sas: Fix warning detected by sparse LKP reports below warning when building for RISC-V with randconfig configuration. drivers/scsi/hisi_sas/hisi_sas_v3_hw.c:4567:35: sparse: sparse: incorrect type in argument 4 (different base types) @@ expected restricted __le32 [usertype] *[assigned] ptr @@ got unsigned int * @@ Type cast to fix this warning. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202307260823.whMNpZ1C-lkp@intel.com/ Signed-off-by: Sunil V L Link: https://lore.kernel.org/r/20230726051759.30038-1-sunilvl@ventanamicro.com Reviewed-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 7aad495d78e58..a676558b096b4 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -4582,7 +4582,7 @@ static int debugfs_fifo_data_v3_hw_show(struct seq_file *s, void *p) debugfs_read_fifo_data_v3_hw(phy); debugfs_show_row_32_v3_hw(s, 0, HISI_SAS_FIFO_DATA_DW_SIZE * 4, - phy->fifo.rd_data); + (__le32 *)phy->fifo.rd_data); return 0; } -- GitLab From e0ba8ff46704fc924e2ef0451ba196cbdc0d68f2 Mon Sep 17 00:00:00 2001 From: Bob Pearson Date: Tue, 20 Jun 2023 08:55:19 -0500 Subject: [PATCH 0613/3445] RDMA/rxe: Move work queue code to subroutines This patch: - Moves code to initialize a qp send work queue to a subroutine named rxe_init_sq. - Moves code to initialize a qp recv work queue to a subroutine named rxe_init_rq. - Moves initialization of qp request and response packet queues ahead of work queue initialization so that cleanup of a qp if it is not fully completed can successfully attempt to drain the packet queues without a seg fault. - Makes minor whitespace cleanups. Fixes: 8700e3e7c485 ("Soft RoCE driver") Link: https://lore.kernel.org/r/20230620135519.9365-2-rpearsonhpe@gmail.com Signed-off-by: Bob Pearson Acked-by: Zhu Yanjun Signed-off-by: Jason Gunthorpe --- drivers/infiniband/sw/rxe/rxe_qp.c | 159 ++++++++++++++++++++--------- 1 file changed, 108 insertions(+), 51 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_qp.c b/drivers/infiniband/sw/rxe/rxe_qp.c index a569b111a9d2a..28e379c108bce 100644 --- a/drivers/infiniband/sw/rxe/rxe_qp.c +++ b/drivers/infiniband/sw/rxe/rxe_qp.c @@ -183,13 +183,63 @@ static void rxe_qp_init_misc(struct rxe_dev *rxe, struct rxe_qp *qp, atomic_set(&qp->skb_out, 0); } +static int rxe_init_sq(struct rxe_qp *qp, struct ib_qp_init_attr *init, + struct ib_udata *udata, + struct rxe_create_qp_resp __user *uresp) +{ + struct rxe_dev *rxe = to_rdev(qp->ibqp.device); + int wqe_size; + int err; + + qp->sq.max_wr = init->cap.max_send_wr; + wqe_size = max_t(int, init->cap.max_send_sge * sizeof(struct ib_sge), + init->cap.max_inline_data); + qp->sq.max_sge = wqe_size / sizeof(struct ib_sge); + qp->sq.max_inline = wqe_size; + wqe_size += sizeof(struct rxe_send_wqe); + + qp->sq.queue = rxe_queue_init(rxe, &qp->sq.max_wr, wqe_size, + QUEUE_TYPE_FROM_CLIENT); + if (!qp->sq.queue) { + rxe_err_qp(qp, "Unable to allocate send queue"); + err = -ENOMEM; + goto err_out; + } + + /* prepare info for caller to mmap send queue if user space qp */ + err = do_mmap_info(rxe, uresp ? &uresp->sq_mi : NULL, udata, + qp->sq.queue->buf, qp->sq.queue->buf_size, + &qp->sq.queue->ip); + if (err) { + rxe_err_qp(qp, "do_mmap_info failed, err = %d", err); + goto err_free; + } + + /* return actual capabilities to caller which may be larger + * than requested + */ + init->cap.max_send_wr = qp->sq.max_wr; + init->cap.max_send_sge = qp->sq.max_sge; + init->cap.max_inline_data = qp->sq.max_inline; + + return 0; + +err_free: + vfree(qp->sq.queue->buf); + kfree(qp->sq.queue); + qp->sq.queue = NULL; +err_out: + return err; +} + static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp, struct ib_qp_init_attr *init, struct ib_udata *udata, struct rxe_create_qp_resp __user *uresp) { int err; - int wqe_size; - enum queue_type type; + + /* if we don't finish qp create make sure queue is valid */ + skb_queue_head_init(&qp->req_pkts); err = sock_create_kern(&init_net, AF_INET, SOCK_DGRAM, 0, &qp->sk); if (err < 0) @@ -204,32 +254,10 @@ static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp, * (0xc000 - 0xffff). */ qp->src_port = RXE_ROCE_V2_SPORT + (hash_32(qp_num(qp), 14) & 0x3fff); - qp->sq.max_wr = init->cap.max_send_wr; - - /* These caps are limited by rxe_qp_chk_cap() done by the caller */ - wqe_size = max_t(int, init->cap.max_send_sge * sizeof(struct ib_sge), - init->cap.max_inline_data); - qp->sq.max_sge = init->cap.max_send_sge = - wqe_size / sizeof(struct ib_sge); - qp->sq.max_inline = init->cap.max_inline_data = wqe_size; - wqe_size += sizeof(struct rxe_send_wqe); - type = QUEUE_TYPE_FROM_CLIENT; - qp->sq.queue = rxe_queue_init(rxe, &qp->sq.max_wr, - wqe_size, type); - if (!qp->sq.queue) - return -ENOMEM; - - err = do_mmap_info(rxe, uresp ? &uresp->sq_mi : NULL, udata, - qp->sq.queue->buf, qp->sq.queue->buf_size, - &qp->sq.queue->ip); - - if (err) { - vfree(qp->sq.queue->buf); - kfree(qp->sq.queue); - qp->sq.queue = NULL; + err = rxe_init_sq(qp, init, udata, uresp); + if (err) return err; - } qp->req.wqe_index = queue_get_producer(qp->sq.queue, QUEUE_TYPE_FROM_CLIENT); @@ -248,36 +276,65 @@ static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp, return 0; } +static int rxe_init_rq(struct rxe_qp *qp, struct ib_qp_init_attr *init, + struct ib_udata *udata, + struct rxe_create_qp_resp __user *uresp) +{ + struct rxe_dev *rxe = to_rdev(qp->ibqp.device); + int wqe_size; + int err; + + qp->rq.max_wr = init->cap.max_recv_wr; + qp->rq.max_sge = init->cap.max_recv_sge; + wqe_size = sizeof(struct rxe_recv_wqe) + + qp->rq.max_sge*sizeof(struct ib_sge); + + qp->rq.queue = rxe_queue_init(rxe, &qp->rq.max_wr, wqe_size, + QUEUE_TYPE_FROM_CLIENT); + if (!qp->rq.queue) { + rxe_err_qp(qp, "Unable to allocate recv queue"); + err = -ENOMEM; + goto err_out; + } + + /* prepare info for caller to mmap recv queue if user space qp */ + err = do_mmap_info(rxe, uresp ? &uresp->rq_mi : NULL, udata, + qp->rq.queue->buf, qp->rq.queue->buf_size, + &qp->rq.queue->ip); + if (err) { + rxe_err_qp(qp, "do_mmap_info failed, err = %d", err); + goto err_free; + } + + /* return actual capabilities to caller which may be larger + * than requested + */ + init->cap.max_recv_wr = qp->rq.max_wr; + + return 0; + +err_free: + vfree(qp->rq.queue->buf); + kfree(qp->rq.queue); + qp->rq.queue = NULL; +err_out: + return err; +} + static int rxe_qp_init_resp(struct rxe_dev *rxe, struct rxe_qp *qp, struct ib_qp_init_attr *init, struct ib_udata *udata, struct rxe_create_qp_resp __user *uresp) { int err; - int wqe_size; - enum queue_type type; + + /* if we don't finish qp create make sure queue is valid */ + skb_queue_head_init(&qp->resp_pkts); if (!qp->srq) { - qp->rq.max_wr = init->cap.max_recv_wr; - qp->rq.max_sge = init->cap.max_recv_sge; - - wqe_size = rcv_wqe_size(qp->rq.max_sge); - - type = QUEUE_TYPE_FROM_CLIENT; - qp->rq.queue = rxe_queue_init(rxe, &qp->rq.max_wr, - wqe_size, type); - if (!qp->rq.queue) - return -ENOMEM; - - err = do_mmap_info(rxe, uresp ? &uresp->rq_mi : NULL, udata, - qp->rq.queue->buf, qp->rq.queue->buf_size, - &qp->rq.queue->ip); - if (err) { - vfree(qp->rq.queue->buf); - kfree(qp->rq.queue); - qp->rq.queue = NULL; + err = rxe_init_rq(qp, init, udata, uresp); + if (err) return err; - } } rxe_init_task(&qp->resp.task, qp, rxe_responder); @@ -307,10 +364,10 @@ int rxe_qp_from_init(struct rxe_dev *rxe, struct rxe_qp *qp, struct rxe_pd *pd, if (srq) rxe_get(srq); - qp->pd = pd; - qp->rcq = rcq; - qp->scq = scq; - qp->srq = srq; + qp->pd = pd; + qp->rcq = rcq; + qp->scq = scq; + qp->srq = srq; atomic_inc(&rcq->num_wq); atomic_inc(&scq->num_wq); -- GitLab From 5993b75d0bc71cd2b441d174b028fc36180f032c Mon Sep 17 00:00:00 2001 From: Bob Pearson Date: Tue, 20 Jun 2023 08:55:21 -0500 Subject: [PATCH 0614/3445] RDMA/rxe: Fix unsafe drain work queue code If create_qp does not fully succeed it is possible for qp cleanup code to attempt to drain the send or recv work queues before the queues have been created causing a seg fault. This patch checks to see if the queues exist before attempting to drain them. Link: https://lore.kernel.org/r/20230620135519.9365-3-rpearsonhpe@gmail.com Reported-by: syzbot+2da1965168e7dbcba136@syzkaller.appspotmail.com Closes: https://lore.kernel.org/linux-rdma/00000000000012d89205fe7cfe00@google.com/raw Fixes: 49dc9c1f0c7e ("RDMA/rxe: Cleanup reset state handling in rxe_resp.c") Fixes: fbdeb828a21f ("RDMA/rxe: Cleanup error state handling in rxe_comp.c") Signed-off-by: Bob Pearson Signed-off-by: Jason Gunthorpe --- drivers/infiniband/sw/rxe/rxe_comp.c | 4 ++++ drivers/infiniband/sw/rxe/rxe_resp.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c index 5111735aafaed..d0bdc2d8adc82 100644 --- a/drivers/infiniband/sw/rxe/rxe_comp.c +++ b/drivers/infiniband/sw/rxe/rxe_comp.c @@ -597,6 +597,10 @@ static void flush_send_queue(struct rxe_qp *qp, bool notify) struct rxe_queue *q = qp->sq.queue; int err; + /* send queue never got created. nothing to do. */ + if (!qp->sq.queue) + return; + while ((wqe = queue_head(q, q->type))) { if (notify) { err = flush_send_wqe(qp, wqe); diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c index 64c64f5f36a81..da470a925efc7 100644 --- a/drivers/infiniband/sw/rxe/rxe_resp.c +++ b/drivers/infiniband/sw/rxe/rxe_resp.c @@ -1469,6 +1469,10 @@ static void flush_recv_queue(struct rxe_qp *qp, bool notify) return; } + /* recv queue not created. nothing to do. */ + if (!qp->rq.queue) + return; + while ((wqe = queue_head(q, q->type))) { if (notify) { err = flush_recv_wqe(qp, wqe); -- GitLab From cc28f351155def8db209647f2e20a59a7080825b Mon Sep 17 00:00:00 2001 From: Bob Pearson Date: Tue, 20 Jun 2023 09:01:43 -0500 Subject: [PATCH 0615/3445] RDMA/rxe: Fix rxe_modify_srq This patch corrects an error in rxe_modify_srq where if the caller changes the srq size the actual new value is not returned to the caller since it may be larger than what is requested. Additionally it open codes the subroutine rcv_wqe_size() which adds very little value, and makes some whitespace changes. Fixes: 8700e3e7c485 ("Soft RoCE driver") Link: https://lore.kernel.org/r/20230620140142.9452-1-rpearsonhpe@gmail.com Signed-off-by: Bob Pearson Signed-off-by: Jason Gunthorpe --- drivers/infiniband/sw/rxe/rxe_loc.h | 6 --- drivers/infiniband/sw/rxe/rxe_srq.c | 60 +++++++++++++++++------------ 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_loc.h b/drivers/infiniband/sw/rxe/rxe_loc.h index 666e06a82bc9e..4d2a8ef52c850 100644 --- a/drivers/infiniband/sw/rxe/rxe_loc.h +++ b/drivers/infiniband/sw/rxe/rxe_loc.h @@ -136,12 +136,6 @@ static inline int qp_mtu(struct rxe_qp *qp) return IB_MTU_4096; } -static inline int rcv_wqe_size(int max_sge) -{ - return sizeof(struct rxe_recv_wqe) + - max_sge * sizeof(struct ib_sge); -} - void free_rd_atomic_resource(struct resp_res *res); static inline void rxe_advance_resp_resource(struct rxe_qp *qp) diff --git a/drivers/infiniband/sw/rxe/rxe_srq.c b/drivers/infiniband/sw/rxe/rxe_srq.c index 27ca82ec0826b..3661cb627d28a 100644 --- a/drivers/infiniband/sw/rxe/rxe_srq.c +++ b/drivers/infiniband/sw/rxe/rxe_srq.c @@ -45,40 +45,41 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq, struct ib_srq_init_attr *init, struct ib_udata *udata, struct rxe_create_srq_resp __user *uresp) { - int err; - int srq_wqe_size; struct rxe_queue *q; - enum queue_type type; + int wqe_size; + int err; - srq->ibsrq.event_handler = init->event_handler; - srq->ibsrq.srq_context = init->srq_context; - srq->limit = init->attr.srq_limit; - srq->srq_num = srq->elem.index; - srq->rq.max_wr = init->attr.max_wr; - srq->rq.max_sge = init->attr.max_sge; + srq->ibsrq.event_handler = init->event_handler; + srq->ibsrq.srq_context = init->srq_context; + srq->limit = init->attr.srq_limit; + srq->srq_num = srq->elem.index; + srq->rq.max_wr = init->attr.max_wr; + srq->rq.max_sge = init->attr.max_sge; - srq_wqe_size = rcv_wqe_size(srq->rq.max_sge); + wqe_size = sizeof(struct rxe_recv_wqe) + + srq->rq.max_sge*sizeof(struct ib_sge); spin_lock_init(&srq->rq.producer_lock); spin_lock_init(&srq->rq.consumer_lock); - type = QUEUE_TYPE_FROM_CLIENT; - q = rxe_queue_init(rxe, &srq->rq.max_wr, srq_wqe_size, type); + q = rxe_queue_init(rxe, &srq->rq.max_wr, wqe_size, + QUEUE_TYPE_FROM_CLIENT); if (!q) { rxe_dbg_srq(srq, "Unable to allocate queue\n"); - return -ENOMEM; + err = -ENOMEM; + goto err_out; } - srq->rq.queue = q; - err = do_mmap_info(rxe, uresp ? &uresp->mi : NULL, udata, q->buf, q->buf_size, &q->ip); if (err) { - vfree(q->buf); - kfree(q); - return err; + rxe_dbg_srq(srq, "Unable to init mmap info for caller\n"); + goto err_free; } + srq->rq.queue = q; + init->attr.max_wr = srq->rq.max_wr; + if (uresp) { if (copy_to_user(&uresp->srq_num, &srq->srq_num, sizeof(uresp->srq_num))) { @@ -88,6 +89,12 @@ int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq, } return 0; + +err_free: + vfree(q->buf); + kfree(q); +err_out: + return err; } int rxe_srq_chk_attr(struct rxe_dev *rxe, struct rxe_srq *srq, @@ -145,9 +152,10 @@ int rxe_srq_from_attr(struct rxe_dev *rxe, struct rxe_srq *srq, struct ib_srq_attr *attr, enum ib_srq_attr_mask mask, struct rxe_modify_srq_cmd *ucmd, struct ib_udata *udata) { - int err; struct rxe_queue *q = srq->rq.queue; struct mminfo __user *mi = NULL; + int wqe_size; + int err; if (mask & IB_SRQ_MAX_WR) { /* @@ -156,12 +164,16 @@ int rxe_srq_from_attr(struct rxe_dev *rxe, struct rxe_srq *srq, */ mi = u64_to_user_ptr(ucmd->mmap_info_addr); - err = rxe_queue_resize(q, &attr->max_wr, - rcv_wqe_size(srq->rq.max_sge), udata, mi, - &srq->rq.producer_lock, + wqe_size = sizeof(struct rxe_recv_wqe) + + srq->rq.max_sge*sizeof(struct ib_sge); + + err = rxe_queue_resize(q, &attr->max_wr, wqe_size, + udata, mi, &srq->rq.producer_lock, &srq->rq.consumer_lock); if (err) - goto err2; + goto err_free; + + srq->rq.max_wr = attr->max_wr; } if (mask & IB_SRQ_LIMIT) @@ -169,7 +181,7 @@ int rxe_srq_from_attr(struct rxe_dev *rxe, struct rxe_srq *srq, return 0; -err2: +err_free: rxe_queue_cleanup(q); srq->rq.queue = NULL; return err; -- GitLab From 5d122db2ff80cd2aed4dcd630befb56b51ddf947 Mon Sep 17 00:00:00 2001 From: Bob Pearson Date: Fri, 21 Jul 2023 15:07:49 -0500 Subject: [PATCH 0616/3445] RDMA/rxe: Fix incomplete state save in rxe_requester If a send packet is dropped by the IP layer in rxe_requester() the call to rxe_xmit_packet() can fail with err == -EAGAIN. To recover, the state of the wqe is restored to the state before the packet was sent so it can be resent. However, the routines that save and restore the state miss a significnt part of the variable state in the wqe, the dma struct which is used to process through the sge table. And, the state is not saved before the packet is built which modifies the dma struct. Under heavy stress testing with many QPs on a fast node sending large messages to a slow node dropped packets are observed and the resent packets are corrupted because the dma struct was not restored. This patch fixes this behavior and allows the test cases to succeed. Fixes: 3050b9985024 ("IB/rxe: Fix race condition between requester and completer") Link: https://lore.kernel.org/r/20230721200748.4604-1-rpearsonhpe@gmail.com Signed-off-by: Bob Pearson Signed-off-by: Jason Gunthorpe --- drivers/infiniband/sw/rxe/rxe_req.c | 45 ++++++++++++++++------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c index 2171f19494bca..d8c41fd626a94 100644 --- a/drivers/infiniband/sw/rxe/rxe_req.c +++ b/drivers/infiniband/sw/rxe/rxe_req.c @@ -578,10 +578,11 @@ static void save_state(struct rxe_send_wqe *wqe, struct rxe_send_wqe *rollback_wqe, u32 *rollback_psn) { - rollback_wqe->state = wqe->state; + rollback_wqe->state = wqe->state; rollback_wqe->first_psn = wqe->first_psn; - rollback_wqe->last_psn = wqe->last_psn; - *rollback_psn = qp->req.psn; + rollback_wqe->last_psn = wqe->last_psn; + rollback_wqe->dma = wqe->dma; + *rollback_psn = qp->req.psn; } static void rollback_state(struct rxe_send_wqe *wqe, @@ -589,10 +590,11 @@ static void rollback_state(struct rxe_send_wqe *wqe, struct rxe_send_wqe *rollback_wqe, u32 rollback_psn) { - wqe->state = rollback_wqe->state; + wqe->state = rollback_wqe->state; wqe->first_psn = rollback_wqe->first_psn; - wqe->last_psn = rollback_wqe->last_psn; - qp->req.psn = rollback_psn; + wqe->last_psn = rollback_wqe->last_psn; + wqe->dma = rollback_wqe->dma; + qp->req.psn = rollback_psn; } static void update_state(struct rxe_qp *qp, struct rxe_pkt_info *pkt) @@ -797,6 +799,9 @@ int rxe_requester(struct rxe_qp *qp) pkt.mask = rxe_opcode[opcode].mask; pkt.wqe = wqe; + /* save wqe state before we build and send packet */ + save_state(wqe, qp, &rollback_wqe, &rollback_psn); + av = rxe_get_av(&pkt, &ah); if (unlikely(!av)) { rxe_dbg_qp(qp, "Failed no address vector\n"); @@ -829,29 +834,29 @@ int rxe_requester(struct rxe_qp *qp) if (ah) rxe_put(ah); - /* - * To prevent a race on wqe access between requester and completer, - * wqe members state and psn need to be set before calling - * rxe_xmit_packet(). - * Otherwise, completer might initiate an unjustified retry flow. - */ - save_state(wqe, qp, &rollback_wqe, &rollback_psn); + /* update wqe state as though we had sent it */ update_wqe_state(qp, wqe, &pkt); update_wqe_psn(qp, wqe, &pkt, payload); err = rxe_xmit_packet(qp, &pkt, skb); if (err) { - qp->need_req_skb = 1; + if (err != -EAGAIN) { + wqe->status = IB_WC_LOC_QP_OP_ERR; + goto err; + } + /* the packet was dropped so reset wqe to the state + * before we sent it so we can try to resend + */ rollback_state(wqe, qp, &rollback_wqe, rollback_psn); - if (err == -EAGAIN) { - rxe_sched_task(&qp->req.task); - goto exit; - } + /* force a delay until the dropped packet is freed and + * the send queue is drained below the low water mark + */ + qp->need_req_skb = 1; - wqe->status = IB_WC_LOC_QP_OP_ERR; - goto err; + rxe_sched_task(&qp->req.task); + goto exit; } update_state(qp, &pkt); -- GitLab From 2897f1925be9a3fad3972660ca4bb0909cd64f35 Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Mon, 31 Jul 2023 21:59:16 +0800 Subject: [PATCH 0617/3445] RDMA/hns: Remove unused function declarations commit b16f8188472e ("RDMA/hns: Refactor eq code for hip06") left behind hns_roce_cleanup_eq_table(). commit 773f841ab1ae ("RDMA/hns: Avoid filling sgid index when modifying QP to RTR") leave hns_get_gid_index() unused. Remove both. Link: https://lore.kernel.org/r/20230731135916.32392-1-yuehaibing@huawei.com Signed-off-by: Yue Haibing Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_device.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 6084c16490006..34e099efaae3e 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -1111,7 +1111,6 @@ int hns_roce_init_qp_table(struct hns_roce_dev *hr_dev); void hns_roce_init_srq_table(struct hns_roce_dev *hr_dev); void hns_roce_init_xrcd_table(struct hns_roce_dev *hr_dev); -void hns_roce_cleanup_eq_table(struct hns_roce_dev *hr_dev); void hns_roce_cleanup_cq_table(struct hns_roce_dev *hr_dev); void hns_roce_cleanup_qp_table(struct hns_roce_dev *hr_dev); @@ -1205,7 +1204,6 @@ void hns_roce_cq_event(struct hns_roce_dev *hr_dev, u32 cqn, int event_type); void flush_cqe(struct hns_roce_dev *dev, struct hns_roce_qp *qp); void hns_roce_qp_event(struct hns_roce_dev *hr_dev, u32 qpn, int event_type); void hns_roce_srq_event(struct hns_roce_dev *hr_dev, u32 srqn, int event_type); -u8 hns_get_gid_index(struct hns_roce_dev *hr_dev, u32 port, int gid_index); void hns_roce_handle_device_err(struct hns_roce_dev *hr_dev); int hns_roce_init(struct hns_roce_dev *hr_dev); void hns_roce_exit(struct hns_roce_dev *hr_dev); -- GitLab From 7d3d20dee4f648ec44e9717d5f647d594d184433 Mon Sep 17 00:00:00 2001 From: Oleksandr Natalenko Date: Mon, 31 Jul 2023 10:40:32 +0200 Subject: [PATCH 0618/3445] scsi: qedf: Do not touch __user pointer in qedf_dbg_stop_io_on_error_cmd_read() directly The qedf_dbg_stop_io_on_error_cmd_read() function invokes sprintf() directly on a __user pointer, which may crash the kernel. Avoid doing that by using a small on-stack buffer for scnprintf() and then calling simple_read_from_buffer() which does a proper copy_to_user() call. Fixes: 61d8658b4a43 ("scsi: qedf: Add QLogic FastLinQ offload FCoE driver framework.") Link: https://lore.kernel.org/lkml/20230724120241.40495-1-oleksandr@redhat.com/ Link: https://lore.kernel.org/linux-scsi/20230726101236.11922-1-skashyap@marvell.com/ Cc: Saurav Kashyap Cc: Rob Evers Cc: Johannes Thumshirn Cc: David Laight Cc: Jozef Bacik Cc: Laurence Oberman Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" Cc: GR-QLogic-Storage-Upstream@marvell.com Cc: linux-scsi@vger.kernel.org Reviewed-by: Laurence Oberman Reviewed-by: Johannes Thumshirn Tested-by: Laurence Oberman Acked-by: Saurav Kashyap Signed-off-by: Oleksandr Natalenko Link: https://lore.kernel.org/r/20230731084034.37021-2-oleksandr@redhat.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qedf/qedf_debugfs.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/qedf/qedf_debugfs.c b/drivers/scsi/qedf/qedf_debugfs.c index a3ed681c8ce3f..3eb4334ac6a32 100644 --- a/drivers/scsi/qedf/qedf_debugfs.c +++ b/drivers/scsi/qedf/qedf_debugfs.c @@ -185,18 +185,17 @@ qedf_dbg_stop_io_on_error_cmd_read(struct file *filp, char __user *buffer, size_t count, loff_t *ppos) { int cnt; + char cbuf[7]; struct qedf_dbg_ctx *qedf_dbg = (struct qedf_dbg_ctx *)filp->private_data; struct qedf_ctx *qedf = container_of(qedf_dbg, struct qedf_ctx, dbg_ctx); QEDF_INFO(qedf_dbg, QEDF_LOG_DEBUGFS, "entered\n"); - cnt = sprintf(buffer, "%s\n", + cnt = scnprintf(cbuf, sizeof(cbuf), "%s\n", qedf->stop_io_on_error ? "true" : "false"); - cnt = min_t(int, count, cnt - *ppos); - *ppos += cnt; - return cnt; + return simple_read_from_buffer(buffer, count, ppos, cbuf, cnt); } static ssize_t -- GitLab From 31b5991a9a91ba97237ac9da509d78eec453ff72 Mon Sep 17 00:00:00 2001 From: Oleksandr Natalenko Date: Mon, 31 Jul 2023 10:40:33 +0200 Subject: [PATCH 0619/3445] scsi: qedf: Do not touch __user pointer in qedf_dbg_debug_cmd_read() directly The qedf_dbg_debug_cmd_read() function invokes sprintf() directly on a __user pointer, which may crash the kernel. Avoid doing that by using a small on-stack buffer for scnprintf() and then calling simple_read_from_buffer() which does a proper copy_to_user() call. Fixes: 61d8658b4a43 ("scsi: qedf: Add QLogic FastLinQ offload FCoE driver framework.") Link: https://lore.kernel.org/lkml/20230724120241.40495-1-oleksandr@redhat.com/ Link: https://lore.kernel.org/linux-scsi/20230726101236.11922-1-skashyap@marvell.com/ Cc: Saurav Kashyap Cc: Rob Evers Cc: Johannes Thumshirn Cc: David Laight Cc: Jozef Bacik Cc: Laurence Oberman Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" Cc: GR-QLogic-Storage-Upstream@marvell.com Cc: linux-scsi@vger.kernel.org Reviewed-by: Laurence Oberman Reviewed-by: Johannes Thumshirn Tested-by: Laurence Oberman Acked-by: Saurav Kashyap Signed-off-by: Oleksandr Natalenko Link: https://lore.kernel.org/r/20230731084034.37021-3-oleksandr@redhat.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qedf/qedf_debugfs.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/qedf/qedf_debugfs.c b/drivers/scsi/qedf/qedf_debugfs.c index 3eb4334ac6a32..1c5716540e465 100644 --- a/drivers/scsi/qedf/qedf_debugfs.c +++ b/drivers/scsi/qedf/qedf_debugfs.c @@ -138,15 +138,14 @@ qedf_dbg_debug_cmd_read(struct file *filp, char __user *buffer, size_t count, loff_t *ppos) { int cnt; + char cbuf[32]; struct qedf_dbg_ctx *qedf_dbg = (struct qedf_dbg_ctx *)filp->private_data; QEDF_INFO(qedf_dbg, QEDF_LOG_DEBUGFS, "debug mask=0x%x\n", qedf_debug); - cnt = sprintf(buffer, "debug mask = 0x%x\n", qedf_debug); + cnt = scnprintf(cbuf, sizeof(cbuf), "debug mask = 0x%x\n", qedf_debug); - cnt = min_t(int, count, cnt - *ppos); - *ppos += cnt; - return cnt; + return simple_read_from_buffer(buffer, count, ppos, cbuf, cnt); } static ssize_t -- GitLab From 25dbc20deab5165f847b4eb42f376f725a986ee8 Mon Sep 17 00:00:00 2001 From: Oleksandr Natalenko Date: Mon, 31 Jul 2023 10:40:34 +0200 Subject: [PATCH 0620/3445] scsi: qedf: Do not touch __user pointer in qedf_dbg_fp_int_cmd_read() directly The qedf_dbg_fp_int_cmd_read() function invokes sprintf() directly on a __user pointer, which may crash the kernel. Avoid doing that by vmalloc()'ating a buffer for scnprintf() and then calling simple_read_from_buffer() which does a proper copy_to_user() call. Fixes: 61d8658b4a43 ("scsi: qedf: Add QLogic FastLinQ offload FCoE driver framework.") Link: https://lore.kernel.org/lkml/20230724120241.40495-1-oleksandr@redhat.com/ Link: https://lore.kernel.org/linux-scsi/20230726101236.11922-1-skashyap@marvell.com/ Cc: Saurav Kashyap Cc: Rob Evers Cc: Johannes Thumshirn Cc: David Laight Cc: Jozef Bacik Cc: Laurence Oberman Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" Cc: GR-QLogic-Storage-Upstream@marvell.com Cc: linux-scsi@vger.kernel.org Reviewed-by: Laurence Oberman Reviewed-by: Johannes Thumshirn Tested-by: Laurence Oberman Acked-by: Saurav Kashyap Signed-off-by: Oleksandr Natalenko Link: https://lore.kernel.org/r/20230731084034.37021-4-oleksandr@redhat.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qedf/qedf_dbg.h | 2 ++ drivers/scsi/qedf/qedf_debugfs.c | 21 +++++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/qedf/qedf_dbg.h b/drivers/scsi/qedf/qedf_dbg.h index f4d81127239eb..5ec2b817c694a 100644 --- a/drivers/scsi/qedf/qedf_dbg.h +++ b/drivers/scsi/qedf/qedf_dbg.h @@ -59,6 +59,8 @@ extern uint qedf_debug; #define QEDF_LOG_NOTICE 0x40000000 /* Notice logs */ #define QEDF_LOG_WARN 0x80000000 /* Warning logs */ +#define QEDF_DEBUGFS_LOG_LEN (2 * PAGE_SIZE) + /* Debug context structure */ struct qedf_dbg_ctx { unsigned int host_no; diff --git a/drivers/scsi/qedf/qedf_debugfs.c b/drivers/scsi/qedf/qedf_debugfs.c index 1c5716540e465..451fd236bfd05 100644 --- a/drivers/scsi/qedf/qedf_debugfs.c +++ b/drivers/scsi/qedf/qedf_debugfs.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "qedf.h" #include "qedf_dbg.h" @@ -98,7 +99,9 @@ static ssize_t qedf_dbg_fp_int_cmd_read(struct file *filp, char __user *buffer, size_t count, loff_t *ppos) { + ssize_t ret; size_t cnt = 0; + char *cbuf; int id; struct qedf_fastpath *fp = NULL; struct qedf_dbg_ctx *qedf_dbg = @@ -108,19 +111,25 @@ qedf_dbg_fp_int_cmd_read(struct file *filp, char __user *buffer, size_t count, QEDF_INFO(qedf_dbg, QEDF_LOG_DEBUGFS, "entered\n"); - cnt = sprintf(buffer, "\nFastpath I/O completions\n\n"); + cbuf = vmalloc(QEDF_DEBUGFS_LOG_LEN); + if (!cbuf) + return 0; + + cnt += scnprintf(cbuf + cnt, QEDF_DEBUGFS_LOG_LEN - cnt, "\nFastpath I/O completions\n\n"); for (id = 0; id < qedf->num_queues; id++) { fp = &(qedf->fp_array[id]); if (fp->sb_id == QEDF_SB_ID_NULL) continue; - cnt += sprintf((buffer + cnt), "#%d: %lu\n", id, - fp->completions); + cnt += scnprintf(cbuf + cnt, QEDF_DEBUGFS_LOG_LEN - cnt, + "#%d: %lu\n", id, fp->completions); } - cnt = min_t(int, count, cnt - *ppos); - *ppos += cnt; - return cnt; + ret = simple_read_from_buffer(buffer, count, ppos, cbuf, cnt); + + vfree(cbuf); + + return ret; } static ssize_t -- GitLab From e0d01da2cb0f1274a4efe9489d4200acd55e3e20 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 31 Jul 2023 20:20:19 +0530 Subject: [PATCH 0621/3445] scsi: ufs: core: Add enums for UFS lanes Since there are enums available for UFS gears, let's add enums for lanes as well to maintain uniformity. Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20230731145020.41262-2-manivannan.sadhasivam@linaro.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 4 ++-- drivers/ufs/host/ufshcd-pltfrm.c | 4 ++-- include/ufs/unipro.h | 6 ++++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 27e1a4914837c..c12c8e3c0b418 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -4375,8 +4375,8 @@ static void ufshcd_init_pwr_info(struct ufs_hba *hba) { hba->pwr_info.gear_rx = UFS_PWM_G1; hba->pwr_info.gear_tx = UFS_PWM_G1; - hba->pwr_info.lane_rx = 1; - hba->pwr_info.lane_tx = 1; + hba->pwr_info.lane_rx = UFS_LANE_1; + hba->pwr_info.lane_tx = UFS_LANE_1; hba->pwr_info.pwr_rx = SLOWAUTO_MODE; hba->pwr_info.pwr_tx = SLOWAUTO_MODE; hba->pwr_info.hs_rate = 0; diff --git a/drivers/ufs/host/ufshcd-pltfrm.c b/drivers/ufs/host/ufshcd-pltfrm.c index 0b7430033047d..7005046e8a692 100644 --- a/drivers/ufs/host/ufshcd-pltfrm.c +++ b/drivers/ufs/host/ufshcd-pltfrm.c @@ -305,8 +305,8 @@ EXPORT_SYMBOL_GPL(ufshcd_get_pwr_dev_param); void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param) { *dev_param = (struct ufs_dev_params){ - .tx_lanes = 2, - .rx_lanes = 2, + .tx_lanes = UFS_LANE_2, + .rx_lanes = UFS_LANE_2, .hs_rx_gear = UFS_HS_G3, .hs_tx_gear = UFS_HS_G3, .pwm_rx_gear = UFS_PWM_G4, diff --git a/include/ufs/unipro.h b/include/ufs/unipro.h index dc9dd1d23f0f7..256eb3a43f540 100644 --- a/include/ufs/unipro.h +++ b/include/ufs/unipro.h @@ -230,6 +230,12 @@ enum ufs_hs_gear_tag { UFS_HS_G5 /* HS Gear 5 */ }; +enum ufs_lanes { + UFS_LANE_DONT_CHANGE, /* Don't change Lane */ + UFS_LANE_1, /* Lane 1 (default for reset) */ + UFS_LANE_2, /* Lane 2 */ +}; + enum ufs_unipro_ver { UFS_UNIPRO_VER_RESERVED = 0, UFS_UNIPRO_VER_1_40 = 1, /* UniPro version 1.40 */ -- GitLab From 03ce80a1bb869f735de793f04c9c085b61884599 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 31 Jul 2023 20:20:20 +0530 Subject: [PATCH 0622/3445] scsi: ufs: qcom: Add support for scaling interconnects Qcom SoCs require scaling the interconnect paths for proper working of the peripherals connected through interconnects. Even for accessing the UFS controller, someone should setup the interconnect paths. So far, the bootloaders used to setup the interconnect paths before booting Linux as they need to access the UFS storage for things like fetching boot firmware. But with the advent of multi boot options, bootloader nowadays like in SA8540p SoC do not setup the interconnect paths at all. So trying to configure UFS in the absence of the interconnect path configuration results in a boot crash. To fix this issue, and also to dynamically scale the interconnects (UFS-DDR and CPU-UFS), interconnect API support is added to the Qcom UFS driver. With this support, the interconnect paths are scaled dynamically based on the gear configuration. During the early stage of ufs_qcom_init(), ufs_qcom_icc_init() will setup the paths to max bandwidth to allow configuring the UFS registers. Touching the registers without configuring the icc paths would result in a crash. However, we don't really need to set max vote for the icc paths as any minimal vote would suffice. But the max value would allow initialization to be done faster. After init, the bandwidth will get updated using ufs_qcom_icc_update_bw() based on the gear and lane configuration. The bandwidth values defined in ufs_qcom_bw_table struct are taken from Qcom downstream vendor devicetree source and are calculated as per the UFS3.1 Spec, Section 6.4.1, HS Gear Rates. So it is fixed across platforms. Cc: Brian Masney Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20230731145020.41262-3-manivannan.sadhasivam@linaro.org Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 131 +++++++++++++++++++++++++++++++++++- drivers/ufs/host/ufs-qcom.h | 3 + 2 files changed, 133 insertions(+), 1 deletion(-) diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 5728e94b6527b..75a1fd295f34f 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,49 @@ enum { TSTBUS_MAX, }; +#define QCOM_UFS_MAX_GEAR 4 +#define QCOM_UFS_MAX_LANE 2 + +enum { + MODE_MIN, + MODE_PWM, + MODE_HS_RA, + MODE_HS_RB, + MODE_MAX, +}; + +struct __ufs_qcom_bw_table { + u32 mem_bw; + u32 cfg_bw; +} ufs_qcom_bw_table[MODE_MAX + 1][QCOM_UFS_MAX_GEAR + 1][QCOM_UFS_MAX_LANE + 1] = { + [MODE_MIN][0][0] = { 0, 0 }, /* Bandwidth values in KB/s */ + [MODE_PWM][UFS_PWM_G1][UFS_LANE_1] = { 922, 1000 }, + [MODE_PWM][UFS_PWM_G2][UFS_LANE_1] = { 1844, 1000 }, + [MODE_PWM][UFS_PWM_G3][UFS_LANE_1] = { 3688, 1000 }, + [MODE_PWM][UFS_PWM_G4][UFS_LANE_1] = { 7376, 1000 }, + [MODE_PWM][UFS_PWM_G1][UFS_LANE_2] = { 1844, 1000 }, + [MODE_PWM][UFS_PWM_G2][UFS_LANE_2] = { 3688, 1000 }, + [MODE_PWM][UFS_PWM_G3][UFS_LANE_2] = { 7376, 1000 }, + [MODE_PWM][UFS_PWM_G4][UFS_LANE_2] = { 14752, 1000 }, + [MODE_HS_RA][UFS_HS_G1][UFS_LANE_1] = { 127796, 1000 }, + [MODE_HS_RA][UFS_HS_G2][UFS_LANE_1] = { 255591, 1000 }, + [MODE_HS_RA][UFS_HS_G3][UFS_LANE_1] = { 1492582, 102400 }, + [MODE_HS_RA][UFS_HS_G4][UFS_LANE_1] = { 2915200, 204800 }, + [MODE_HS_RA][UFS_HS_G1][UFS_LANE_2] = { 255591, 1000 }, + [MODE_HS_RA][UFS_HS_G2][UFS_LANE_2] = { 511181, 1000 }, + [MODE_HS_RA][UFS_HS_G3][UFS_LANE_2] = { 1492582, 204800 }, + [MODE_HS_RA][UFS_HS_G4][UFS_LANE_2] = { 2915200, 409600 }, + [MODE_HS_RB][UFS_HS_G1][UFS_LANE_1] = { 149422, 1000 }, + [MODE_HS_RB][UFS_HS_G2][UFS_LANE_1] = { 298189, 1000 }, + [MODE_HS_RB][UFS_HS_G3][UFS_LANE_1] = { 1492582, 102400 }, + [MODE_HS_RB][UFS_HS_G4][UFS_LANE_1] = { 2915200, 204800 }, + [MODE_HS_RB][UFS_HS_G1][UFS_LANE_2] = { 298189, 1000 }, + [MODE_HS_RB][UFS_HS_G2][UFS_LANE_2] = { 596378, 1000 }, + [MODE_HS_RB][UFS_HS_G3][UFS_LANE_2] = { 1492582, 204800 }, + [MODE_HS_RB][UFS_HS_G4][UFS_LANE_2] = { 2915200, 409600 }, + [MODE_MAX][0][0] = { 7643136, 307200 }, +}; + static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS]; static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host); @@ -789,6 +833,51 @@ static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_qcom_host *host, bool enable) } } +static int ufs_qcom_icc_set_bw(struct ufs_qcom_host *host, u32 mem_bw, u32 cfg_bw) +{ + struct device *dev = host->hba->dev; + int ret; + + ret = icc_set_bw(host->icc_ddr, 0, mem_bw); + if (ret < 0) { + dev_err(dev, "failed to set bandwidth request: %d\n", ret); + return ret; + } + + ret = icc_set_bw(host->icc_cpu, 0, cfg_bw); + if (ret < 0) { + dev_err(dev, "failed to set bandwidth request: %d\n", ret); + return ret; + } + + return 0; +} + +static struct __ufs_qcom_bw_table ufs_qcom_get_bw_table(struct ufs_qcom_host *host) +{ + struct ufs_pa_layer_attr *p = &host->dev_req_params; + int gear = max_t(u32, p->gear_rx, p->gear_tx); + int lane = max_t(u32, p->lane_rx, p->lane_tx); + + if (ufshcd_is_hs_mode(p)) { + if (p->hs_rate == PA_HS_MODE_B) + return ufs_qcom_bw_table[MODE_HS_RB][gear][lane]; + else + return ufs_qcom_bw_table[MODE_HS_RA][gear][lane]; + } else { + return ufs_qcom_bw_table[MODE_PWM][gear][lane]; + } +} + +static int ufs_qcom_icc_update_bw(struct ufs_qcom_host *host) +{ + struct __ufs_qcom_bw_table bw_table; + + bw_table = ufs_qcom_get_bw_table(host); + + return ufs_qcom_icc_set_bw(host, bw_table.mem_bw, bw_table.cfg_bw); +} + static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, enum ufs_notify_change_status status, struct ufs_pa_layer_attr *dev_max_params, @@ -852,6 +941,8 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, memcpy(&host->dev_req_params, dev_req_params, sizeof(*dev_req_params)); + ufs_qcom_icc_update_bw(host); + /* disable the device ref clock if entered PWM mode */ if (ufshcd_is_hs_mode(&hba->pwr_info) && !ufshcd_is_hs_mode(dev_req_params)) @@ -981,7 +1072,9 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, switch (status) { case PRE_CHANGE: - if (!on) { + if (on) { + ufs_qcom_icc_update_bw(host); + } else { if (!ufs_qcom_is_link_active(hba)) { /* disable device ref_clk */ ufs_qcom_dev_ref_clk_ctrl(host, false); @@ -993,6 +1086,9 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, /* enable the device ref clock for HS mode*/ if (ufshcd_is_hs_mode(&hba->pwr_info)) ufs_qcom_dev_ref_clk_ctrl(host, true); + } else { + ufs_qcom_icc_set_bw(host, ufs_qcom_bw_table[MODE_MIN][0][0].mem_bw, + ufs_qcom_bw_table[MODE_MIN][0][0].cfg_bw); } break; } @@ -1031,6 +1127,34 @@ static const struct reset_control_ops ufs_qcom_reset_ops = { .deassert = ufs_qcom_reset_deassert, }; +static int ufs_qcom_icc_init(struct ufs_qcom_host *host) +{ + struct device *dev = host->hba->dev; + int ret; + + host->icc_ddr = devm_of_icc_get(dev, "ufs-ddr"); + if (IS_ERR(host->icc_ddr)) + return dev_err_probe(dev, PTR_ERR(host->icc_ddr), + "failed to acquire interconnect path\n"); + + host->icc_cpu = devm_of_icc_get(dev, "cpu-ufs"); + if (IS_ERR(host->icc_cpu)) + return dev_err_probe(dev, PTR_ERR(host->icc_cpu), + "failed to acquire interconnect path\n"); + + /* + * Set Maximum bandwidth vote before initializing the UFS controller and + * device. Ideally, a minimal interconnect vote would suffice for the + * initialization, but a max vote would allow faster initialization. + */ + ret = ufs_qcom_icc_set_bw(host, ufs_qcom_bw_table[MODE_MAX][0][0].mem_bw, + ufs_qcom_bw_table[MODE_MAX][0][0].cfg_bw); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to set bandwidth request\n"); + + return 0; +} + /** * ufs_qcom_init - bind phy with controller * @hba: host controller instance @@ -1085,6 +1209,10 @@ static int ufs_qcom_init(struct ufs_hba *hba) } } + err = ufs_qcom_icc_init(host); + if (err) + goto out_variant_clear; + host->device_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(host->device_reset)) { @@ -1282,6 +1410,7 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, dev_req_params->pwr_rx, dev_req_params->hs_rate, false); + ufs_qcom_icc_update_bw(host); ufshcd_uic_hibern8_exit(hba); } diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index 729240367e702..d6f8e74bd5381 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -206,6 +206,9 @@ struct ufs_qcom_host { struct clk *tx_l1_sync_clk; bool is_lane_clks_enabled; + struct icc_path *icc_ddr; + struct icc_path *icc_cpu; + #ifdef CONFIG_SCSI_UFS_CRYPTO struct qcom_ice *ice; #endif -- GitLab From 3a17fefe0f1960d3f120de986129682f36bc89db Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 27 Jul 2023 12:41:13 -0700 Subject: [PATCH 0623/3445] scsi: ufs: Follow the kernel-doc syntax for documenting return values Use 'Return:' to document the return value instead of 'Returns' as required by the kernel-doc documentation. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20230727194457.3152309-2-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-mcq.c | 10 +- drivers/ufs/core/ufshcd-priv.h | 2 +- drivers/ufs/core/ufshcd.c | 186 +++++++++++++++-------------- drivers/ufs/host/cdns-pltfrm.c | 10 +- drivers/ufs/host/tc-dwc-g210-pci.c | 2 +- drivers/ufs/host/tc-dwc-g210.c | 12 +- drivers/ufs/host/ufs-mediatek.c | 6 +- drivers/ufs/host/ufs-qcom.c | 8 +- drivers/ufs/host/ufshcd-dwc.c | 6 +- drivers/ufs/host/ufshcd-pci.c | 2 +- drivers/ufs/host/ufshcd-pltfrm.c | 4 +- 11 files changed, 126 insertions(+), 122 deletions(-) diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index 1e23ba3e2bdf0..a3d4ef8aa3b92 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -105,7 +105,7 @@ EXPORT_SYMBOL_GPL(ufshcd_mcq_config_mac); * @hba: per adapter instance * @req: pointer to the request to be issued * - * Returns the hardware queue instance on which the request would + * Return: the hardware queue instance on which the request would * be queued. */ struct ufs_hw_queue *ufshcd_mcq_req_to_hwq(struct ufs_hba *hba, @@ -121,7 +121,7 @@ struct ufs_hw_queue *ufshcd_mcq_req_to_hwq(struct ufs_hba *hba, * ufshcd_mcq_decide_queue_depth - decide the queue depth * @hba: per adapter instance * - * Returns queue-depth on success, non-zero on error + * Return: queue-depth on success, non-zero on error * * MAC - Max. Active Command of the Host Controller (HC) * HC wouldn't send more than this commands to the device. @@ -493,7 +493,7 @@ static int ufshcd_mcq_sq_start(struct ufs_hba *hba, struct ufs_hw_queue *hwq) * @hba: per adapter instance. * @task_tag: The command's task tag. * - * Returns 0 for success; error code otherwise. + * Return: 0 for success; error code otherwise. */ int ufshcd_mcq_sq_cleanup(struct ufs_hba *hba, int task_tag) { @@ -575,7 +575,7 @@ static void ufshcd_mcq_nullify_sqe(struct utp_transfer_req_desc *utrd) * @hwq: Hardware Queue to be searched. * @task_tag: The command's task tag. * - * Returns true if the SQE containing the command is present in the SQ + * Return: true if the SQE containing the command is present in the SQ * (not fetched by the controller); returns false if the SQE is not in the SQ. */ static bool ufshcd_mcq_sqe_search(struct ufs_hba *hba, @@ -624,7 +624,7 @@ out: * ufshcd_mcq_abort - Abort the command in MCQ. * @cmd: The command to be aborted. * - * Returns SUCCESS or FAILED error codes + * Return: SUCCESS or FAILED error codes */ int ufshcd_mcq_abort(struct scsi_cmnd *cmd) { diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index 0f3bd943b58b1..4feccd5c1ba2e 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -294,7 +294,7 @@ extern const struct ufs_pm_lvl_states ufs_pm_lvl_states[]; * ufshcd_scsi_to_upiu_lun - maps scsi LUN to UPIU LUN * @scsi_lun: scsi LUN id * - * Returns UPIU LUN id + * Return: UPIU LUN id */ static inline u8 ufshcd_scsi_to_upiu_lun(unsigned int scsi_lun) { diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 27e1a4914837c..d7b83230ddbbd 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -701,8 +701,7 @@ EXPORT_SYMBOL_GPL(ufshcd_delay_us); * @interval_us: polling interval in microseconds * @timeout_ms: timeout in milliseconds * - * Return: - * -ETIMEDOUT on error, zero on success. + * Return: -ETIMEDOUT on error, zero on success. */ static int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask, u32 val, unsigned long interval_us, @@ -730,7 +729,7 @@ static int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask, * ufshcd_get_intr_mask - Get the interrupt bit mask * @hba: Pointer to adapter instance * - * Returns interrupt bit mask per version + * Return: interrupt bit mask per version */ static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba) { @@ -746,7 +745,7 @@ static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba) * ufshcd_get_ufs_version - Get the UFS version supported by the HBA * @hba: Pointer to adapter instance * - * Returns UFSHCI version supported by the controller + * Return: UFSHCI version supported by the controller */ static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba) { @@ -773,7 +772,7 @@ static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba) * the host controller * @hba: pointer to adapter instance * - * Returns true if device present, false if no device detected + * Return: true if device present, false if no device detected */ static inline bool ufshcd_is_device_present(struct ufs_hba *hba) { @@ -786,7 +785,8 @@ static inline bool ufshcd_is_device_present(struct ufs_hba *hba) * @cqe: pointer to the completion queue entry * * This function is used to get the OCS field from UTRD - * Returns the OCS field in the UTRD + * + * Return: the OCS field in the UTRD. */ static enum utp_ocs ufshcd_get_tr_ocs(struct ufshcd_lrb *lrbp, struct cq_entry *cqe) @@ -839,7 +839,7 @@ static inline void ufshcd_utmrl_clear(struct ufs_hba *hba, u32 pos) * ufshcd_get_lists_status - Check UCRDY, UTRLRDY and UTMRLRDY * @reg: Register value of host controller status * - * Returns integer, 0 on Success and positive value if failed + * Return: 0 on success; a positive value if failed. */ static inline int ufshcd_get_lists_status(u32 reg) { @@ -851,7 +851,8 @@ static inline int ufshcd_get_lists_status(u32 reg) * @hba: Pointer to adapter instance * * This function gets the result of UIC command completion - * Returns 0 on success, non zero value on error + * + * Return: 0 on success; non-zero value on error. */ static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba) { @@ -864,7 +865,8 @@ static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba) * @hba: Pointer to adapter instance * * This function gets UIC command argument3 - * Returns 0 on success, non zero value on error + * + * Return: 0 on success; non-zero value on error. */ static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba) { @@ -886,7 +888,8 @@ ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr) * @ucd_rsp_ptr: pointer to response UPIU * * This function gets the response status and scsi_status from response UPIU - * Returns the response result code. + * + * Return: the response result code. */ static inline int ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp *ucd_rsp_ptr) @@ -899,7 +902,7 @@ ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp *ucd_rsp_ptr) * from response UPIU * @ucd_rsp_ptr: pointer to response UPIU * - * Return the data segment length. + * Return: the data segment length. */ static inline unsigned int ufshcd_get_rsp_upiu_data_seg_len(struct utp_upiu_rsp *ucd_rsp_ptr) @@ -915,7 +918,7 @@ ufshcd_get_rsp_upiu_data_seg_len(struct utp_upiu_rsp *ucd_rsp_ptr) * The function checks if the device raised an exception event indicated in * the Device Information field of response UPIU. * - * Returns true if exception is raised, false otherwise. + * Return: true if exception is raised, false otherwise. */ static inline bool ufshcd_is_exception_event(struct utp_upiu_rsp *ucd_rsp_ptr) { @@ -991,7 +994,7 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba) * ufshcd_is_hba_active - Get controller state * @hba: per adapter instance * - * Returns true if and only if the controller is active. + * Return: true if and only if the controller is active. */ static inline bool ufshcd_is_hba_active(struct ufs_hba *hba) { @@ -1027,8 +1030,7 @@ static bool ufshcd_is_unipro_pa_params_tuning_req(struct ufs_hba *hba) * @hba: per adapter instance * @scale_up: If True, set max possible frequency othewise set low frequency * - * Returns 0 if successful - * Returns < 0 for any other errors + * Return: 0 if successful; < 0 upon failure. */ static int ufshcd_set_clk_freq(struct ufs_hba *hba, bool scale_up) { @@ -1090,8 +1092,7 @@ out: * @hba: per adapter instance * @scale_up: True if scaling up and false if scaling down * - * Returns 0 if successful - * Returns < 0 for any other errors + * Return: 0 if successful; < 0 upon failure. */ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up) { @@ -1122,7 +1123,7 @@ out: * @hba: per adapter instance * @scale_up: True if scaling up and false if scaling down * - * Returns true if scaling is required, false otherwise. + * Return: true if scaling is required, false otherwise. */ static bool ufshcd_is_devfreq_scaling_required(struct ufs_hba *hba, bool scale_up) @@ -1239,9 +1240,8 @@ out: * @hba: per adapter instance * @scale_up: True for scaling up gear and false for scaling down * - * Returns 0 for success, - * Returns -EBUSY if scaling can't happen at this time - * Returns non-zero for any other errors + * Return: 0 for success; -EBUSY if scaling can't happen at this time; + * non-zero for any other errors. */ static int ufshcd_scale_gear(struct ufs_hba *hba, bool scale_up) { @@ -1331,9 +1331,8 @@ static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, int err, bool sc * @hba: per adapter instance * @scale_up: True for scaling up and false for scalin down * - * Returns 0 for success, - * Returns -EBUSY if scaling can't happen at this time - * Returns non-zero for any other errors + * Return: 0 for success; -EBUSY if scaling can't happen at this time; non-zero + * for any other errors. */ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up) { @@ -2318,7 +2317,8 @@ static inline int ufshcd_hba_capabilities(struct ufs_hba *hba) * ufshcd_ready_for_uic_cmd - Check if controller is ready * to accept UIC commands * @hba: per adapter instance - * Return true on success, else false + * + * Return: true on success, else false. */ static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba) { @@ -2330,7 +2330,8 @@ static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba) * @hba: Pointer to adapter instance * * This function gets the UPMCRS field of HCS register - * Returns value of UPMCRS field + * + * Return: value of UPMCRS field. */ static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba) { @@ -2368,7 +2369,7 @@ ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) * @hba: per adapter instance * @uic_cmd: UIC command * - * Returns 0 only if success. + * Return: 0 only if success. */ static int ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) @@ -2407,7 +2408,7 @@ ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) * @uic_cmd: UIC command * @completion: initialize the completion only if this is set to true * - * Returns 0 only if success. + * Return: 0 only if success. */ static int __ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd, @@ -2436,7 +2437,7 @@ __ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd, * @hba: per adapter instance * @uic_cmd: UIC command * - * Returns 0 only if success. + * Return: 0 only if success. */ int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) { @@ -2513,7 +2514,7 @@ static void ufshcd_sgl_to_prdt(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, int * @hba: per adapter instance * @lrbp: pointer to local reference block * - * Returns 0 in case of success, non-zero value in case of failure + * Return: 0 in case of success, non-zero value in case of failure. */ static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) { @@ -2765,7 +2766,7 @@ static int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) * ufshcd_upiu_wlun_to_scsi_wlun - maps UPIU W-LUN id to SCSI W-LUN ID * @upiu_wlun_id: UPIU W-LUN id * - * Returns SCSI W-LUN id + * Return: SCSI W-LUN id. */ static inline u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 upiu_wlun_id) { @@ -2836,7 +2837,7 @@ static void ufshcd_init_lrb(struct ufs_hba *hba, struct ufshcd_lrb *lrb, int i) * @host: SCSI host pointer * @cmd: command from SCSI Midlayer * - * Returns 0 for success, non-zero in case of failure + * Return: 0 for success, non-zero in case of failure. */ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) { @@ -2947,7 +2948,7 @@ static int ufshcd_compose_dev_cmd(struct ufs_hba *hba, * Check with the block layer if the command is inflight * @cmd: command to check. * - * Returns true if command is inflight; false if not. + * Return: true if command is inflight; false if not. */ bool ufshcd_cmd_inflight(struct scsi_cmnd *cmd) { @@ -3245,7 +3246,7 @@ static int ufshcd_query_flag_retry(struct ufs_hba *hba, * @index: flag index to access * @flag_res: the flag value after the query request completes * - * Returns 0 for success, non-zero in case of failure + * Return: 0 for success, non-zero in case of failure. */ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, enum flag_idn idn, u8 index, bool *flag_res) @@ -3314,7 +3315,7 @@ out_unlock: * @selector: selector field * @attr_val: the attribute value after the query request completes * - * Returns 0 for success, non-zero in case of failure + * Return: 0 for success, non-zero in case of failure. */ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, enum attr_idn idn, u8 index, u8 selector, u32 *attr_val) @@ -3379,7 +3380,7 @@ out_unlock: * @attr_val: the attribute value after the query request * completes * - * Returns 0 for success, non-zero in case of failure + * Return: 0 for success, non-zero in case of failure. */ int ufshcd_query_attr_retry(struct ufs_hba *hba, enum query_opcode opcode, enum attr_idn idn, u8 index, u8 selector, @@ -3477,9 +3478,10 @@ out_unlock: * @desc_buf: the buffer that contains the descriptor * @buf_len: length parameter passed to the device * - * Returns 0 for success, non-zero in case of failure. * The buf_len parameter will contain, on return, the length parameter * received on the response. + * + * Return: 0 for success, non-zero in case of failure. */ int ufshcd_query_descriptor_retry(struct ufs_hba *hba, enum query_opcode opcode, @@ -3509,7 +3511,7 @@ int ufshcd_query_descriptor_retry(struct ufs_hba *hba, * @param_read_buf: pointer to buffer where parameter would be read * @param_size: sizeof(param_read_buf) * - * Return 0 in case of success, non-zero otherwise + * Return: 0 in case of success, non-zero otherwise. */ int ufshcd_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id, @@ -3689,7 +3691,7 @@ out: * @param_read_buf: pointer to buffer where parameter would be read * @param_size: sizeof(param_read_buf) * - * Return 0 in case of success, non-zero otherwise + * Return: 0 in case of success, non-zero otherwise. */ static inline int ufshcd_read_unit_desc_param(struct ufs_hba *hba, int lun, @@ -3744,7 +3746,7 @@ static int ufshcd_get_ref_clk_gating_wait(struct ufs_hba *hba) * (UTMRDL) * 4. Allocate memory for local reference block(lrb). * - * Returns 0 for success, non-zero in case of failure + * Return: 0 for success, non-zero in case of failure. */ static int ufshcd_memory_alloc(struct ufs_hba *hba) { @@ -3891,7 +3893,7 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba) * Once the Unipro links are up, the device connected to the controller * is detected. * - * Returns 0 on success, non-zero value on failure + * Return: 0 on success, non-zero value on failure. */ static int ufshcd_dme_link_startup(struct ufs_hba *hba) { @@ -3913,7 +3915,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba) * DME_RESET command is issued in order to reset UniPro stack. * This function now deals with cold reset. * - * Returns 0 on success, non-zero value on failure + * Return: 0 on success, non-zero value on failure. */ static int ufshcd_dme_reset(struct ufs_hba *hba) { @@ -3952,7 +3954,7 @@ EXPORT_SYMBOL_GPL(ufshcd_dme_configure_adapt); * * DME_ENABLE command is issued in order to enable UniPro stack. * - * Returns 0 on success, non-zero value on failure + * Return: 0 on success, non-zero value on failure. */ static int ufshcd_dme_enable(struct ufs_hba *hba) { @@ -4008,7 +4010,7 @@ static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba) * @mib_val: setting value as uic command argument3 * @peer: indicate whether peer or local * - * Returns 0 on success, non-zero value on failure + * Return: 0 on success, non-zero value on failure. */ int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel, u8 attr_set, u32 mib_val, u8 peer) @@ -4052,7 +4054,7 @@ EXPORT_SYMBOL_GPL(ufshcd_dme_set_attr); * @mib_val: the value of the attribute as returned by the UIC command * @peer: indicate whether peer or local * - * Returns 0 on success, non-zero value on failure + * Return: 0 on success, non-zero value on failure. */ int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, u32 *mib_val, u8 peer) @@ -4133,7 +4135,7 @@ EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr); * addition to normal UIC command completion Status (UCCS). This function only * returns after the relevant status bits indicate the completion. * - * Returns 0 on success, non-zero value on failure + * Return: 0 on success, non-zero value on failure. */ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd) { @@ -4223,7 +4225,7 @@ out_unlock: * @hba: per adapter instance * @mode: powr mode value * - * Returns 0 on success, non-zero value on failure + * Return: 0 on success, non-zero value on failure. */ int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode) { @@ -4616,7 +4618,7 @@ out: * 3. Program UTRL and UTMRL base address * 4. Configure run-stop-registers * - * Returns 0 on success, non-zero value on failure + * Return: 0 on success, non-zero value on failure. */ int ufshcd_make_hba_operational(struct ufs_hba *hba) { @@ -4697,7 +4699,7 @@ EXPORT_SYMBOL_GPL(ufshcd_hba_stop); * sequence kicks off. When controller is ready it will set * the Host Controller Enable bit to 1. * - * Returns 0 on success, non-zero value on failure + * Return: 0 on success, non-zero value on failure. */ static int ufshcd_hba_execute_hce(struct ufs_hba *hba) { @@ -4842,7 +4844,7 @@ EXPORT_SYMBOL_GPL(ufshcd_update_evt_hist); * ufshcd_link_startup - Initialize unipro link startup * @hba: per adapter instance * - * Returns 0 for success, non-zero in case of failure + * Return: 0 for success, non-zero in case of failure. */ static int ufshcd_link_startup(struct ufs_hba *hba) { @@ -5061,7 +5063,7 @@ set_qdepth: * ufshcd_slave_alloc - handle initial SCSI device configurations * @sdev: pointer to SCSI device * - * Returns success + * Return: success. */ static int ufshcd_slave_alloc(struct scsi_device *sdev) { @@ -5179,7 +5181,7 @@ static void ufshcd_slave_destroy(struct scsi_device *sdev) * @lrbp: pointer to local reference block of completed command * @scsi_status: SCSI command status * - * Returns value base on SCSI command status + * Return: value base on SCSI command status. */ static inline int ufshcd_scsi_cmd_status(struct ufshcd_lrb *lrbp, int scsi_status) @@ -5213,7 +5215,7 @@ ufshcd_scsi_cmd_status(struct ufshcd_lrb *lrbp, int scsi_status) * @lrbp: pointer to local reference block of completed command * @cqe: pointer to the completion queue entry * - * Returns result of the command to notify SCSI midlayer + * Return: result of the command to notify SCSI midlayer. */ static inline int ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, @@ -5348,7 +5350,7 @@ static bool ufshcd_is_auto_hibern8_error(struct ufs_hba *hba, * @hba: per adapter instance * @intr_status: interrupt status generated by the controller * - * Returns + * Return: * IRQ_HANDLED - If interrupt is valid * IRQ_NONE - If invalid interrupt */ @@ -5468,7 +5470,7 @@ static void ufshcd_clear_polled(struct ufs_hba *hba, } /* - * Returns > 0 if one or more commands have been completed or 0 if no + * Return: > 0 if one or more commands have been completed or 0 if no * requests have been completed. */ static int ufshcd_poll(struct Scsi_Host *shost, unsigned int queue_num) @@ -5558,7 +5560,7 @@ static void ufshcd_mcq_compl_pending_transfer(struct ufs_hba *hba, * ufshcd_transfer_req_compl - handle SCSI and query command completion * @hba: per adapter instance * - * Returns + * Return: * IRQ_HANDLED - If interrupt is valid * IRQ_NONE - If invalid interrupt */ @@ -5635,7 +5637,7 @@ int ufshcd_update_ee_control(struct ufs_hba *hba, u16 *mask, * Disables exception event in the device so that the EVENT_ALERT * bit is not set. * - * Returns zero on success, non-zero error value on failure. + * Return: zero on success, non-zero error value on failure. */ static inline int ufshcd_disable_ee(struct ufs_hba *hba, u16 mask) { @@ -5650,7 +5652,7 @@ static inline int ufshcd_disable_ee(struct ufs_hba *hba, u16 mask) * Enable corresponding exception event in the device to allow * device to alert host in critical scenarios. * - * Returns zero on success, non-zero error value on failure. + * Return: zero on success, non-zero error value on failure. */ static inline int ufshcd_enable_ee(struct ufs_hba *hba, u16 mask) { @@ -5666,7 +5668,7 @@ static inline int ufshcd_enable_ee(struct ufs_hba *hba, u16 mask) * as the device is allowed to manage its own way of handling background * operations. * - * Returns zero on success, non-zero on failure. + * Return: zero on success, non-zero on failure. */ static int ufshcd_enable_auto_bkops(struct ufs_hba *hba) { @@ -5705,7 +5707,7 @@ out: * host is idle so that BKOPS are managed effectively without any negative * impacts. * - * Returns zero on success, non-zero on failure. + * Return: zero on success, non-zero on failure. */ static int ufshcd_disable_auto_bkops(struct ufs_hba *hba) { @@ -5781,7 +5783,7 @@ static inline int ufshcd_get_bkops_status(struct ufs_hba *hba, u32 *status) * bkops_status is greater than or equal to "status" argument passed to * this function, disable otherwise. * - * Returns 0 for success, non-zero in case of failure. + * Return: 0 for success, non-zero in case of failure. * * NOTE: Caller of this function can check the "hba->auto_bkops_enabled" flag * to know whether auto bkops is enabled or disabled after this function @@ -6133,7 +6135,7 @@ static void ufshcd_complete_requests(struct ufs_hba *hba, bool force_compl) * to recover from the DL NAC errors or not. * @hba: per-adapter instance * - * Returns true if error handling is required, false otherwise + * Return: true if error handling is required, false otherwise. */ static bool ufshcd_quirk_dl_nac_errors(struct ufs_hba *hba) { @@ -6594,7 +6596,7 @@ skip_err_handling: * ufshcd_update_uic_error - check and set fatal UIC error flags. * @hba: per-adapter instance * - * Returns + * Return: * IRQ_HANDLED - If interrupt is valid * IRQ_NONE - If invalid interrupt */ @@ -6687,7 +6689,7 @@ static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba) * @hba: per-adapter instance * @intr_status: interrupt status generated by the controller * - * Returns + * Return: * IRQ_HANDLED - If interrupt is valid * IRQ_NONE - If invalid interrupt */ @@ -6763,7 +6765,7 @@ static irqreturn_t ufshcd_check_errors(struct ufs_hba *hba, u32 intr_status) * ufshcd_tmc_handler - handle task management function completion * @hba: per adapter instance * - * Returns + * Return: * IRQ_HANDLED - If interrupt is valid * IRQ_NONE - If invalid interrupt */ @@ -6792,7 +6794,7 @@ static irqreturn_t ufshcd_tmc_handler(struct ufs_hba *hba) * ufshcd_handle_mcq_cq_events - handle MCQ completion queue events * @hba: per adapter instance * - * Returns IRQ_HANDLED if interrupt is handled + * Return: IRQ_HANDLED if interrupt is handled. */ static irqreturn_t ufshcd_handle_mcq_cq_events(struct ufs_hba *hba) { @@ -6827,7 +6829,7 @@ static irqreturn_t ufshcd_handle_mcq_cq_events(struct ufs_hba *hba) * @hba: per adapter instance * @intr_status: contains interrupts generated by the controller * - * Returns + * Return: * IRQ_HANDLED - If interrupt is valid * IRQ_NONE - If invalid interrupt */ @@ -6858,7 +6860,7 @@ static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status) * @irq: irq number * @__hba: pointer to adapter instance * - * Returns + * Return: * IRQ_HANDLED - If interrupt is valid * IRQ_NONE - If invalid interrupt */ @@ -7007,7 +7009,7 @@ static int __ufshcd_issue_tm_cmd(struct ufs_hba *hba, * @tm_function: task management function opcode * @tm_response: task management service response return value * - * Returns non-zero value on error, zero on success. + * Return: non-zero value on error, zero on success. */ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id, u8 tm_function, u8 *tm_response) @@ -7231,7 +7233,7 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, * @sg_list: Pointer to SG list when DATA IN/OUT UPIU is required in ARPMB operation * @dir: DMA direction * - * Returns zero on success, non-zero on failure + * Return: zero on success, non-zero on failure. */ int ufshcd_advanced_rpmb_req_handler(struct ufs_hba *hba, struct utp_upiu_req *req_upiu, struct utp_upiu_req *rsp_upiu, struct ufs_ehs *req_ehs, @@ -7317,7 +7319,7 @@ int ufshcd_advanced_rpmb_req_handler(struct ufs_hba *hba, struct utp_upiu_req *r * ufshcd_eh_device_reset_handler() - Reset a single logical unit. * @cmd: SCSI command pointer * - * Returns SUCCESS/FAILED + * Return: SUCCESS or FAILED. */ static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd) { @@ -7412,7 +7414,7 @@ static void ufshcd_set_req_abort_skip(struct ufs_hba *hba, unsigned long bitmap) * issued. To avoid that, first issue UFS_QUERY_TASK to check if the command is * really issued and then try to abort it. * - * Returns zero on success, non-zero on failure + * Return: zero on success, non-zero on failure. */ int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag) { @@ -7500,7 +7502,7 @@ out: * ufshcd_abort - scsi host template eh_abort_handler callback * @cmd: SCSI command pointer * - * Returns SUCCESS/FAILED + * Return: SUCCESS or FAILED. */ static int ufshcd_abort(struct scsi_cmnd *cmd) { @@ -7625,7 +7627,7 @@ release: * local and remote (device) Uni-Pro stack and the attributes * are reset to default state. * - * Returns zero on success, non-zero on failure + * Return: zero on success, non-zero on failure. */ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba) { @@ -7662,7 +7664,7 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba) * Reset and recover device, host and re-establish link. This * is helpful to recover the communication in fatal error conditions. * - * Returns zero on success, non-zero on failure + * Return: zero on success, non-zero on failure. */ static int ufshcd_reset_and_restore(struct ufs_hba *hba) { @@ -7720,7 +7722,7 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba) * ufshcd_eh_host_reset_handler - host reset handler registered to scsi layer * @cmd: SCSI command pointer * - * Returns SUCCESS/FAILED + * Return: SUCCESS or FAILED. */ static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd) { @@ -7752,7 +7754,7 @@ static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd) * @start_scan: row at the desc table to start scan from * @buff: power descriptor buffer * - * Returns calculated max ICC level for specific regulator + * Return: calculated max ICC level for specific regulator. */ static u32 ufshcd_get_max_icc_level(int sup_curr_uA, u32 start_scan, const char *buff) @@ -7798,7 +7800,7 @@ static u32 ufshcd_get_max_icc_level(int sup_curr_uA, u32 start_scan, * @hba: per-adapter instance * @desc_buf: power descriptor buffer to extract ICC levels from. * - * Returns calculated ICC level + * Return: calculated ICC level. */ static u32 ufshcd_find_max_sup_active_icc_level(struct ufs_hba *hba, const u8 *desc_buf) @@ -7907,7 +7909,7 @@ static inline void ufshcd_blk_pm_runtime_init(struct scsi_device *sdev) * This function adds scsi device instances for each of all well known LUs * (except "REPORT LUNS" LU). * - * Returns zero on success (all required W-LUs are added successfully), + * Return: zero on success (all required W-LUs are added successfully), * non-zero error value on failure (if failed to add any of the required W-LU). */ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba) @@ -8176,7 +8178,7 @@ static void ufs_put_device_desc(struct ufs_hba *hba) * RX_MIN_ACTIVATETIME_CAPABILITY attribute. This optimal value can help reduce * the hibern8 exit latency. * - * Returns zero on success, non-zero error value on failure. + * Return: zero on success, non-zero error value on failure. */ static int ufshcd_tune_pa_tactivate(struct ufs_hba *hba) { @@ -8211,7 +8213,7 @@ out: * TX_HIBERN8TIME_CAPABILITY & peer M-PHY's RX_HIBERN8TIME_CAPABILITY. * This optimal value can help reduce the hibern8 exit latency. * - * Returns zero on success, non-zero error value on failure. + * Return: zero on success, non-zero error value on failure. */ static int ufshcd_tune_pa_hibern8time(struct ufs_hba *hba) { @@ -8253,7 +8255,7 @@ out: * PA_TACTIVATE, we need to enable UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE quirk * for such devices. * - * Returns zero on success, non-zero error value on failure. + * Return: zero on success, non-zero error value on failure. */ static int ufshcd_quirk_tune_host_pa_tactivate(struct ufs_hba *hba) { @@ -9255,8 +9257,8 @@ static int ufshcd_execute_start_stop(struct scsi_device *sdev, * @hba: per adapter instance * @pwr_mode: device power mode to set * - * Returns 0 if requested power mode is set successfully - * Returns < 0 if failed to set the requested power mode + * Return: 0 if requested power mode is set successfully; + * < 0 if failed to set the requested power mode. */ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, enum ufs_dev_pwr_mode pwr_mode) @@ -9876,7 +9878,7 @@ static int ufshcd_suspend(struct ufs_hba *hba) * This function basically turns on the regulators, clocks and * irqs of the hba. * - * Returns 0 for success and non-zero for failure + * Return: 0 for success and non-zero for failure. */ static int ufshcd_resume(struct ufs_hba *hba) { @@ -9917,7 +9919,7 @@ out: * Executed before putting the system into a sleep state in which the contents * of main memory are preserved. * - * Returns 0 for success and non-zero for failure + * Return: 0 for success and non-zero for failure. */ int ufshcd_system_suspend(struct device *dev) { @@ -9944,7 +9946,7 @@ EXPORT_SYMBOL(ufshcd_system_suspend); * Executed after waking the system up from a sleep state in which the contents * of main memory were preserved. * - * Returns 0 for success and non-zero for failure + * Return: 0 for success and non-zero for failure. */ int ufshcd_system_resume(struct device *dev) { @@ -9974,7 +9976,7 @@ EXPORT_SYMBOL(ufshcd_system_resume); * * Check the description of ufshcd_suspend() function for more details. * - * Returns 0 for success and non-zero for failure + * Return: 0 for success and non-zero for failure. */ int ufshcd_runtime_suspend(struct device *dev) { @@ -10134,7 +10136,7 @@ EXPORT_SYMBOL_GPL(ufshcd_dealloc_host); * addressing capability * @hba: per adapter instance * - * Returns 0 for success, non-zero for failure + * Return: 0 for success, non-zero for failure. */ static int ufshcd_set_dma_mask(struct ufs_hba *hba) { @@ -10149,7 +10151,8 @@ static int ufshcd_set_dma_mask(struct ufs_hba *hba) * ufshcd_alloc_host - allocate Host Bus Adapter (HBA) * @dev: pointer to device handle * @hba_handle: driver private handle - * Returns 0 on success, non-zero value on failure + * + * Return: 0 on success, non-zero value on failure. */ int ufshcd_alloc_host(struct device *dev, struct ufs_hba **hba_handle) { @@ -10205,7 +10208,8 @@ static const struct blk_mq_ops ufshcd_tmf_ops = { * @hba: per-adapter instance * @mmio_base: base register address * @irq: Interrupt line of device - * Returns 0 on success, non-zero value on failure + * + * Return: 0 on success, non-zero value on failure. */ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) { diff --git a/drivers/ufs/host/cdns-pltfrm.c b/drivers/ufs/host/cdns-pltfrm.c index 26761425a76ca..5b1e1e26d1332 100644 --- a/drivers/ufs/host/cdns-pltfrm.c +++ b/drivers/ufs/host/cdns-pltfrm.c @@ -105,7 +105,7 @@ static void cdns_ufs_set_l4_attr(struct ufs_hba *hba) * Sets HCLKDIV register value based on the core_clk * @hba: host controller instance * - * Return zero for success and non-zero for failure + * Return: zero for success and non-zero for failure. */ static int cdns_ufs_set_hclkdiv(struct ufs_hba *hba) { @@ -148,7 +148,7 @@ static int cdns_ufs_set_hclkdiv(struct ufs_hba *hba) * @hba: host controller instance * @status: notify stage (pre, post change) * - * Return zero for success and non-zero for failure + * Return: zero for success and non-zero for failure. */ static int cdns_ufs_hce_enable_notify(struct ufs_hba *hba, enum ufs_notify_change_status status) @@ -182,7 +182,7 @@ static void cdns_ufs_hibern8_notify(struct ufs_hba *hba, enum uic_cmd_dme cmd, * @hba: host controller instance * @status: notify stage (pre, post change) * - * Return zero for success and non-zero for failure + * Return: zero for success and non-zero for failure. */ static int cdns_ufs_link_startup_notify(struct ufs_hba *hba, enum ufs_notify_change_status status) @@ -212,7 +212,7 @@ static int cdns_ufs_link_startup_notify(struct ufs_hba *hba, * cdns_ufs_init - performs additional ufs initialization * @hba: host controller instance * - * Returns status of initialization + * Return: status of initialization. */ static int cdns_ufs_init(struct ufs_hba *hba) { @@ -284,7 +284,7 @@ MODULE_DEVICE_TABLE(of, cdns_ufs_of_match); * cdns_ufs_pltfrm_probe - probe routine of the driver * @pdev: pointer to platform device handle * - * Return zero for success and non-zero for failure + * Return: zero for success and non-zero for failure. */ static int cdns_ufs_pltfrm_probe(struct platform_device *pdev) { diff --git a/drivers/ufs/host/tc-dwc-g210-pci.c b/drivers/ufs/host/tc-dwc-g210-pci.c index f96fe58558417..876781fd6861e 100644 --- a/drivers/ufs/host/tc-dwc-g210-pci.c +++ b/drivers/ufs/host/tc-dwc-g210-pci.c @@ -51,7 +51,7 @@ static void tc_dwc_g210_pci_remove(struct pci_dev *pdev) * @pdev: pointer to PCI device handle * @id: PCI device id * - * Returns 0 on success, non-zero value on failure + * Return: 0 on success, non-zero value on failure. */ static int tc_dwc_g210_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/ufs/host/tc-dwc-g210.c b/drivers/ufs/host/tc-dwc-g210.c index deb93dbd83a43..84a8b915b745b 100644 --- a/drivers/ufs/host/tc-dwc-g210.c +++ b/drivers/ufs/host/tc-dwc-g210.c @@ -21,7 +21,7 @@ * This function configures Synopsys TC specific atributes (40-bit RMMI) * @hba: Pointer to drivers structure * - * Returns 0 on success or non-zero value on failure + * Return: 0 on success or non-zero value on failure. */ static int tc_dwc_g210_setup_40bit_rmmi(struct ufs_hba *hba) { @@ -85,7 +85,7 @@ static int tc_dwc_g210_setup_40bit_rmmi(struct ufs_hba *hba) * This function configures Synopsys TC 20-bit RMMI Lane 0 * @hba: Pointer to drivers structure * - * Returns 0 on success or non-zero value on failure + * Return: 0 on success or non-zero value on failure. */ static int tc_dwc_g210_setup_20bit_rmmi_lane0(struct ufs_hba *hba) { @@ -138,7 +138,7 @@ static int tc_dwc_g210_setup_20bit_rmmi_lane0(struct ufs_hba *hba) * This function configures Synopsys TC 20-bit RMMI Lane 1 * @hba: Pointer to drivers structure * - * Returns 0 on success or non-zero value on failure + * Return: 0 on success or non-zero value on failure. */ static int tc_dwc_g210_setup_20bit_rmmi_lane1(struct ufs_hba *hba) { @@ -215,7 +215,7 @@ out: * This function configures Synopsys TC specific atributes (20-bit RMMI) * @hba: Pointer to drivers structure * - * Returns 0 on success or non-zero value on failure + * Return: 0 on success or non-zero value on failure. */ static int tc_dwc_g210_setup_20bit_rmmi(struct ufs_hba *hba) { @@ -256,7 +256,7 @@ out: * * @hba: Pointer to drivers structure * - * Returns 0 on success non-zero value on failure + * Return: 0 on success non-zero value on failure. */ int tc_dwc_g210_config_40_bit(struct ufs_hba *hba) { @@ -288,7 +288,7 @@ EXPORT_SYMBOL(tc_dwc_g210_config_40_bit); * * @hba: Pointer to drivers structure * - * Returns 0 on success non-zero value on failure + * Return: 0 on success non-zero value on failure. */ int tc_dwc_g210_config_20_bit(struct ufs_hba *hba) { diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index 10a28079c8bb0..2383ecd88f1cb 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -666,7 +666,7 @@ static void ufs_mtk_pwr_ctrl(struct ufs_hba *hba, bool on) * @on: If true, enable clocks else disable them. * @status: PRE_CHANGE or POST_CHANGE notify * - * Returns 0 on success, non-zero on failure. + * Return: 0 on success, non-zero on failure. */ static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on, enum ufs_notify_change_status status) @@ -885,7 +885,7 @@ failed: * Binds PHY with controller and powers up PHY enabling clocks * and regulators. * - * Returns -EPROBE_DEFER if binding fails, returns negative error + * Return: -EPROBE_DEFER if binding fails, returns negative error * on phy power up failure and returns zero on success. */ static int ufs_mtk_init(struct ufs_hba *hba) @@ -1696,7 +1696,7 @@ static const struct ufs_hba_variant_ops ufs_hba_mtk_vops = { * ufs_mtk_probe - probe routine of the driver * @pdev: pointer to Platform device handle * - * Return zero for success and non-zero for failure + * Return: zero for success and non-zero for failure. */ static int ufs_mtk_probe(struct platform_device *pdev) { diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 5728e94b6527b..24b53ae8ca27e 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -485,7 +485,7 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, } /* - * Returns zero for success and non-zero in case of a failure + * Return: zero for success and non-zero in case of a failure. */ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate, bool update_link_startup_timer) @@ -964,7 +964,7 @@ static void ufs_qcom_set_caps(struct ufs_hba *hba) * @on: If true, enable clocks else disable them. * @status: PRE_CHANGE or POST_CHANGE notify * - * Returns 0 on success, non-zero on failure. + * Return: 0 on success, non-zero on failure. */ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, enum ufs_notify_change_status status) @@ -1038,7 +1038,7 @@ static const struct reset_control_ops ufs_qcom_reset_ops = { * Binds PHY with controller and powers up PHY enabling clocks * and regulators. * - * Returns -EPROBE_DEFER if binding fails, returns negative error + * Return: -EPROBE_DEFER if binding fails, returns negative error * on phy power up failure and returns zero on success. */ static int ufs_qcom_init(struct ufs_hba *hba) @@ -1756,7 +1756,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { * ufs_qcom_probe - probe routine of the driver * @pdev: pointer to Platform device handle * - * Return zero for success and non-zero for failure + * Return: zero for success and non-zero for failure. */ static int ufs_qcom_probe(struct platform_device *pdev) { diff --git a/drivers/ufs/host/ufshcd-dwc.c b/drivers/ufs/host/ufshcd-dwc.c index e28a67e1e3145..b547df05a2b99 100644 --- a/drivers/ufs/host/ufshcd-dwc.c +++ b/drivers/ufs/host/ufshcd-dwc.c @@ -51,7 +51,7 @@ static void ufshcd_dwc_program_clk_div(struct ufs_hba *hba, u32 divider_val) * Check if link is up * @hba: private structure pointer * - * Returns 0 on success, non-zero value on failure + * Return: 0 on success, non-zero value on failure. */ static int ufshcd_dwc_link_is_up(struct ufs_hba *hba) { @@ -78,7 +78,7 @@ static int ufshcd_dwc_link_is_up(struct ufs_hba *hba) * * @hba: pointer to drivers private data * - * Returns 0 on success non-zero value on failure + * Return: 0 on success non-zero value on failure. */ static int ufshcd_dwc_connection_setup(struct ufs_hba *hba) { @@ -112,7 +112,7 @@ static int ufshcd_dwc_connection_setup(struct ufs_hba *hba) * @hba: private structure pointer * @status: Callback notify status * - * Returns 0 on success, non-zero value on failure + * Return: 0 on success, non-zero value on failure. */ int ufshcd_dwc_link_startup_notify(struct ufs_hba *hba, enum ufs_notify_change_status status) diff --git a/drivers/ufs/host/ufshcd-pci.c b/drivers/ufs/host/ufshcd-pci.c index cf3987773051f..95df8105265ab 100644 --- a/drivers/ufs/host/ufshcd-pci.c +++ b/drivers/ufs/host/ufshcd-pci.c @@ -524,7 +524,7 @@ static void ufshcd_pci_remove(struct pci_dev *pdev) * @pdev: pointer to PCI device handle * @id: PCI device id * - * Returns 0 on success, non-zero value on failure + * Return: 0 on success, non-zero value on failure. */ static int ufshcd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/ufs/host/ufshcd-pltfrm.c b/drivers/ufs/host/ufshcd-pltfrm.c index 0b7430033047d..34131d36d09f5 100644 --- a/drivers/ufs/host/ufshcd-pltfrm.c +++ b/drivers/ufs/host/ufshcd-pltfrm.c @@ -212,7 +212,7 @@ static void ufshcd_init_lanes_per_dir(struct ufs_hba *hba) * @dev_max: pointer to device attributes * @agreed_pwr: returned agreed attributes * - * Returns 0 on success, non-zero value on failure + * Return: 0 on success, non-zero value on failure. */ int ufshcd_get_pwr_dev_param(const struct ufs_dev_params *pltfrm_param, const struct ufs_pa_layer_attr *dev_max, @@ -326,7 +326,7 @@ EXPORT_SYMBOL_GPL(ufshcd_init_pwr_dev_param); * @pdev: pointer to Platform device handle * @vops: pointer to variant ops * - * Returns 0 on success, non-zero value on failure + * Return: 0 on success, non-zero value on failure. */ int ufshcd_pltfrm_init(struct platform_device *pdev, const struct ufs_hba_variant_ops *vops) -- GitLab From fd4bffb54dc0f6d179c0c09c06de9f6071792a85 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 27 Jul 2023 12:41:14 -0700 Subject: [PATCH 0624/3445] scsi: ufs: Document all return values This patch fixes multiple W=2 kernel-doc warnings. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20230727194457.3152309-3-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs_bsg.c | 2 ++ drivers/ufs/core/ufshcd.c | 38 ++++++++++++++++++++++++++++++++ drivers/ufs/host/cdns-pltfrm.c | 4 ++-- drivers/ufs/host/ufshcd-pltfrm.c | 2 ++ 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/drivers/ufs/core/ufs_bsg.c b/drivers/ufs/core/ufs_bsg.c index 0d38e7fa34cc8..34e423924e065 100644 --- a/drivers/ufs/core/ufs_bsg.c +++ b/drivers/ufs/core/ufs_bsg.c @@ -232,6 +232,8 @@ static inline void ufs_bsg_node_release(struct device *dev) * @hba: per adapter object * * Called during initial loading of the driver, and before scsi_scan_host. + * + * Returns: 0 (success). */ int ufs_bsg_probe(struct ufs_hba *hba) { diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index d7b83230ddbbd..ca520f2b1820e 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -876,6 +876,8 @@ static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba) /** * ufshcd_get_req_rsp - returns the TR response transaction type * @ucd_rsp_ptr: pointer to response UPIU + * + * Return: UPIU type. */ static inline int ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr) @@ -2241,6 +2243,8 @@ static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp) * descriptor * @hba: per adapter instance * @lrbp: pointer to local reference block + * + * Return: 0 upon success; < 0 upon failure. */ static int ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) @@ -2713,6 +2717,8 @@ static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp) * for Device Management Purposes * @hba: per adapter instance * @lrbp: pointer to local reference block + * + * Return: 0 upon success; < 0 upon failure. */ static int ufshcd_compose_devman_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) @@ -2741,6 +2747,8 @@ static int ufshcd_compose_devman_upiu(struct ufs_hba *hba, * for SCSI Purposes * @hba: per adapter instance * @lrbp: pointer to local reference block + * + * Return: 0 upon success; < 0 upon failure. */ static int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) { @@ -3018,6 +3026,8 @@ ufshcd_check_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) * ufshcd_dev_cmd_completion() - handles device management command responses * @hba: per adapter instance * @lrbp: pointer to local reference block + * + * Return: 0 upon success; < 0 upon failure. */ static int ufshcd_dev_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) @@ -3155,6 +3165,8 @@ retry: * @cmd_type: specifies the type (NOP, Query...) * @timeout: timeout in milliseconds * + * Return: 0 upon success; < 0 upon failure. + * * NOTE: Since there is only one available tag for device management commands, * it is expected you hold the hba->dev_cmd.lock mutex. */ @@ -4387,6 +4399,8 @@ static void ufshcd_init_pwr_info(struct ufs_hba *hba) /** * ufshcd_get_max_pwr_mode - reads the max power mode negotiated with device * @hba: per-adapter instance + * + * Return: 0 upon success; < 0 upon failure. */ static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba) { @@ -4544,6 +4558,8 @@ static int ufshcd_change_power_mode(struct ufs_hba *hba, * ufshcd_config_pwr_mode - configure a new power mode * @hba: per-adapter instance * @desired_pwr_mode: desired power configuration + * + * Return: 0 upon success; < 0 upon failure. */ int ufshcd_config_pwr_mode(struct ufs_hba *hba, struct ufs_pa_layer_attr *desired_pwr_mode) @@ -4568,6 +4584,8 @@ EXPORT_SYMBOL_GPL(ufshcd_config_pwr_mode); * @hba: per-adapter instance * * Set fDeviceInit flag and poll until device toggles it. + * + * Return: 0 upon success; < 0 upon failure. */ static int ufshcd_complete_dev_init(struct ufs_hba *hba) { @@ -4939,6 +4957,8 @@ out: * If the UTP layer at the device side is not initialized, it may * not respond with NOP IN UPIU within timeout of %NOP_OUT_TIMEOUT * and we retry sending NOP OUT for %NOP_OUT_RETRIES iterations. + * + * Return: 0 upon success; < 0 upon failure. */ static int ufshcd_verify_dev_init(struct ufs_hba *hba) { @@ -5099,6 +5119,8 @@ static int ufshcd_slave_alloc(struct scsi_device *sdev) * @depth: required depth to set * * Change queue depth and make sure the max. limits are not crossed. + * + * Return: new queue depth. */ static int ufshcd_change_queue_depth(struct scsi_device *sdev, int depth) { @@ -5108,6 +5130,8 @@ static int ufshcd_change_queue_depth(struct scsi_device *sdev, int depth) /** * ufshcd_slave_configure - adjust SCSI device configurations * @sdev: pointer to SCSI device + * + * Return: 0 (success). */ static int ufshcd_slave_configure(struct scsi_device *sdev) { @@ -5824,6 +5848,8 @@ out: * * If BKOPs is enabled, this function returns 0, 1 if the bkops in not enabled * and negative error value for any other failure. + * + * Return: 0 upon success; < 0 upon failure. */ static int ufshcd_urgent_bkops(struct ufs_hba *hba) { @@ -7064,6 +7090,8 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id, * * Since there is only one available tag for device management commands, * the caller is expected to hold the hba->dev_cmd.lock mutex. + * + * Return: 0 upon success; < 0 upon failure. */ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, struct utp_upiu_req *req_upiu, @@ -7165,6 +7193,8 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, * Management requests. * It is up to the caller to fill the upiu conent properly, as it will * be copied without any further input validations. + * + * Return: 0 upon success; < 0 upon failure. */ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, struct utp_upiu_req *req_upiu, @@ -8478,6 +8508,8 @@ out: /** * ufshcd_add_lus - probe and add UFS logical units * @hba: per-adapter instance + * + * Return: 0 upon success; < 0 upon failure. */ static int ufshcd_add_lus(struct ufs_hba *hba) { @@ -8687,6 +8719,8 @@ static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) * @init_dev_params: whether or not to call ufshcd_device_params_init(). * * Execute link-startup and verify device initialization + * + * Return: 0 upon success; < 0 upon failure. */ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) { @@ -9841,6 +9875,8 @@ out: * * This function will put disable irqs, turn off clocks * and set vreg and hba-vreg in lpm mode. + * + * Return: 0 upon success; < 0 upon failure. */ static int ufshcd_suspend(struct ufs_hba *hba) { @@ -10002,6 +10038,8 @@ EXPORT_SYMBOL(ufshcd_runtime_suspend); * * 1. Turn on all the controller related clocks * 2. Turn ON VCC rail + * + * Return: 0 upon success; < 0 upon failure. */ int ufshcd_runtime_resume(struct device *dev) { diff --git a/drivers/ufs/host/cdns-pltfrm.c b/drivers/ufs/host/cdns-pltfrm.c index 5b1e1e26d1332..9c96aa8810acd 100644 --- a/drivers/ufs/host/cdns-pltfrm.c +++ b/drivers/ufs/host/cdns-pltfrm.c @@ -235,7 +235,7 @@ static int cdns_ufs_init(struct ufs_hba *hba) * cdns_ufs_m31_16nm_phy_initialization - performs m31 phy initialization * @hba: host controller instance * - * Always returns 0 + * Return: 0 (success). */ static int cdns_ufs_m31_16nm_phy_initialization(struct ufs_hba *hba) { @@ -308,7 +308,7 @@ static int cdns_ufs_pltfrm_probe(struct platform_device *pdev) * cdns_ufs_pltfrm_remove - removes the ufs driver * @pdev: pointer to platform device handle * - * Always returns 0 + * Return: 0 (success). */ static int cdns_ufs_pltfrm_remove(struct platform_device *pdev) { diff --git a/drivers/ufs/host/ufshcd-pltfrm.c b/drivers/ufs/host/ufshcd-pltfrm.c index 34131d36d09f5..8729f45d4f83a 100644 --- a/drivers/ufs/host/ufshcd-pltfrm.c +++ b/drivers/ufs/host/ufshcd-pltfrm.c @@ -166,6 +166,8 @@ EXPORT_SYMBOL_GPL(ufshcd_populate_vreg); * If any of the supplies are not defined it is assumed that they are always-on * and hence return zero. If the property is defined but parsing is failed * then return corresponding error. + * + * Return: 0 upon success; < 0 upon failure. */ static int ufshcd_parse_regulator_info(struct ufs_hba *hba) { -- GitLab From 8d8af294ce03c9997fff36a20d0e697c6a73c41b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 27 Jul 2023 12:41:15 -0700 Subject: [PATCH 0625/3445] scsi: ufs: Fix kernel-doc headers Fix the remaining kernel-doc warnings that are reported when building with W=2. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20230727194457.3152309-4-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/host/cdns-pltfrm.c | 13 ++++--------- drivers/ufs/host/tc-dwc-g210.c | 20 ++++++-------------- drivers/ufs/host/ufshcd-dwc.c | 16 ++++++---------- 3 files changed, 16 insertions(+), 33 deletions(-) diff --git a/drivers/ufs/host/cdns-pltfrm.c b/drivers/ufs/host/cdns-pltfrm.c index 9c96aa8810acd..2491e7e870283 100644 --- a/drivers/ufs/host/cdns-pltfrm.c +++ b/drivers/ufs/host/cdns-pltfrm.c @@ -101,8 +101,7 @@ static void cdns_ufs_set_l4_attr(struct ufs_hba *hba) } /** - * cdns_ufs_set_hclkdiv() - * Sets HCLKDIV register value based on the core_clk + * cdns_ufs_set_hclkdiv() - set HCLKDIV register value based on the core_clk. * @hba: host controller instance * * Return: zero for success and non-zero for failure. @@ -143,8 +142,7 @@ static int cdns_ufs_set_hclkdiv(struct ufs_hba *hba) } /** - * cdns_ufs_hce_enable_notify() - * Called before and after HCE enable bit is set. + * cdns_ufs_hce_enable_notify() - set HCLKDIV register * @hba: host controller instance * @status: notify stage (pre, post change) * @@ -160,12 +158,10 @@ static int cdns_ufs_hce_enable_notify(struct ufs_hba *hba, } /** - * cdns_ufs_hibern8_notify() - * Called around hibern8 enter/exit. + * cdns_ufs_hibern8_notify() - save and restore L4 attributes. * @hba: host controller instance * @cmd: UIC Command * @status: notify stage (pre, post change) - * */ static void cdns_ufs_hibern8_notify(struct ufs_hba *hba, enum uic_cmd_dme cmd, enum ufs_notify_change_status status) @@ -177,8 +173,7 @@ static void cdns_ufs_hibern8_notify(struct ufs_hba *hba, enum uic_cmd_dme cmd, } /** - * cdns_ufs_link_startup_notify() - * Called before and after Link startup is carried out. + * cdns_ufs_link_startup_notify() - handle link startup. * @hba: host controller instance * @status: notify stage (pre, post change) * diff --git a/drivers/ufs/host/tc-dwc-g210.c b/drivers/ufs/host/tc-dwc-g210.c index 84a8b915b745b..0ac53cc8465ee 100644 --- a/drivers/ufs/host/tc-dwc-g210.c +++ b/drivers/ufs/host/tc-dwc-g210.c @@ -17,8 +17,7 @@ #include "tc-dwc-g210.h" /** - * tc_dwc_g210_setup_40bit_rmmi() - * This function configures Synopsys TC specific atributes (40-bit RMMI) + * tc_dwc_g210_setup_40bit_rmmi() - configure 40-bit RMMI. * @hba: Pointer to drivers structure * * Return: 0 on success or non-zero value on failure. @@ -81,8 +80,7 @@ static int tc_dwc_g210_setup_40bit_rmmi(struct ufs_hba *hba) } /** - * tc_dwc_g210_setup_20bit_rmmi_lane0() - * This function configures Synopsys TC 20-bit RMMI Lane 0 + * tc_dwc_g210_setup_20bit_rmmi_lane0() - configure 20-bit RMMI Lane 0. * @hba: Pointer to drivers structure * * Return: 0 on success or non-zero value on failure. @@ -134,8 +132,7 @@ static int tc_dwc_g210_setup_20bit_rmmi_lane0(struct ufs_hba *hba) } /** - * tc_dwc_g210_setup_20bit_rmmi_lane1() - * This function configures Synopsys TC 20-bit RMMI Lane 1 + * tc_dwc_g210_setup_20bit_rmmi_lane1() - configure 20-bit RMMI Lane 1. * @hba: Pointer to drivers structure * * Return: 0 on success or non-zero value on failure. @@ -211,8 +208,7 @@ out: } /** - * tc_dwc_g210_setup_20bit_rmmi() - * This function configures Synopsys TC specific atributes (20-bit RMMI) + * tc_dwc_g210_setup_20bit_rmmi() - configure 20-bit RMMI. * @hba: Pointer to drivers structure * * Return: 0 on success or non-zero value on failure. @@ -251,9 +247,7 @@ out: } /** - * tc_dwc_g210_config_40_bit() - * This function configures Local (host) Synopsys 40-bit TC specific attributes - * + * tc_dwc_g210_config_40_bit() - configure 40-bit TC specific attributes. * @hba: Pointer to drivers structure * * Return: 0 on success non-zero value on failure. @@ -283,9 +277,7 @@ out: EXPORT_SYMBOL(tc_dwc_g210_config_40_bit); /** - * tc_dwc_g210_config_20_bit() - * This function configures Local (host) Synopsys 20-bit TC specific attributes - * + * tc_dwc_g210_config_20_bit() - configure 20-bit TC specific attributes. * @hba: Pointer to drivers structure * * Return: 0 on success non-zero value on failure. diff --git a/drivers/ufs/host/ufshcd-dwc.c b/drivers/ufs/host/ufshcd-dwc.c index b547df05a2b99..21b1cf912dcc6 100644 --- a/drivers/ufs/host/ufshcd-dwc.c +++ b/drivers/ufs/host/ufshcd-dwc.c @@ -34,9 +34,7 @@ int ufshcd_dwc_dme_set_attrs(struct ufs_hba *hba, EXPORT_SYMBOL(ufshcd_dwc_dme_set_attrs); /** - * ufshcd_dwc_program_clk_div() - * This function programs the clk divider value. This value is needed to - * provide 1 microsecond tick to unipro layer. + * ufshcd_dwc_program_clk_div() - program clock divider. * @hba: Private Structure pointer * @divider_val: clock divider value to be programmed * @@ -47,8 +45,7 @@ static void ufshcd_dwc_program_clk_div(struct ufs_hba *hba, u32 divider_val) } /** - * ufshcd_dwc_link_is_up() - * Check if link is up + * ufshcd_dwc_link_is_up() - check if link is up. * @hba: private structure pointer * * Return: 0 on success, non-zero value on failure. @@ -68,7 +65,9 @@ static int ufshcd_dwc_link_is_up(struct ufs_hba *hba) } /** - * ufshcd_dwc_connection_setup() + * ufshcd_dwc_connection_setup() - configure unipro attributes. + * @hba: pointer to drivers private data + * * This function configures both the local side (host) and the peer side * (device) unipro attributes to establish the connection to application/ * cport. @@ -76,8 +75,6 @@ static int ufshcd_dwc_link_is_up(struct ufs_hba *hba) * have this connection setup on reset. But invoking this function does no * harm and should be fine even working with any ufs device. * - * @hba: pointer to drivers private data - * * Return: 0 on success non-zero value on failure. */ static int ufshcd_dwc_connection_setup(struct ufs_hba *hba) @@ -107,8 +104,7 @@ static int ufshcd_dwc_connection_setup(struct ufs_hba *hba) } /** - * ufshcd_dwc_link_startup_notify() - * UFS Host DWC specific link startup sequence + * ufshcd_dwc_link_startup_notify() - program clock divider. * @hba: private structure pointer * @status: Callback notify status * -- GitLab From f08191520614764789aec42161b297c327d3660a Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 27 Jul 2023 12:41:16 -0700 Subject: [PATCH 0626/3445] scsi: ufs: Rename a function argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch suppresses the following W=2 warning: drivers/ufs/core/ufs-hwmon.c:130:49: warning: declaration of ‘_data’ shadows a global declaration [-Wshadow] Reviewed-by: Avri Altman Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20230727194457.3152309-5-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-hwmon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/ufs/core/ufs-hwmon.c b/drivers/ufs/core/ufs-hwmon.c index 101d7082446fc..34194064367ff 100644 --- a/drivers/ufs/core/ufs-hwmon.c +++ b/drivers/ufs/core/ufs-hwmon.c @@ -127,7 +127,8 @@ static int ufs_hwmon_write(struct device *dev, enum hwmon_sensor_types type, u32 return err; } -static umode_t ufs_hwmon_is_visible(const void *_data, enum hwmon_sensor_types type, u32 attr, +static umode_t ufs_hwmon_is_visible(const void *data, + enum hwmon_sensor_types type, u32 attr, int channel) { if (type != hwmon_temp) -- GitLab From cce9fd602ca0c5b0a310dbe457aa61d1beaa2d38 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 27 Jul 2023 12:41:17 -0700 Subject: [PATCH 0627/3445] scsi: ufs: Minimize #include directives Only #include those header files that are needed. Note: include/ufs/ufshcd.h needs because of SG_ALL. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20230727194457.3152309-6-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- include/ufs/ufs.h | 2 +- include/ufs/ufshcd.h | 1 + include/ufs/ufshci.h | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h index c789252b5fad2..0fb733683953f 100644 --- a/include/ufs/ufs.h +++ b/include/ufs/ufs.h @@ -11,7 +11,7 @@ #ifndef _UFS_H #define _UFS_H -#include +#include #include #include diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index fc80de57a4c64..67bd089e70bc4 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/include/ufs/ufshci.h b/include/ufs/ufshci.h index 146fbea76d98d..c48135554d5cb 100644 --- a/include/ufs/ufshci.h +++ b/include/ufs/ufshci.h @@ -11,7 +11,8 @@ #ifndef _UFSHCI_H #define _UFSHCI_H -#include +#include +#include enum { TASK_REQ_UPIU_SIZE_DWORDS = 8, -- GitLab From f99533bd7e3dc033093f339784bebe0247e1831c Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 27 Jul 2023 12:41:18 -0700 Subject: [PATCH 0628/3445] scsi: ufs: Simplify zero-initialization Use { } instead of { { 0 }, } to zero-initialize data structures on the stack. This patch fixes two W=2 warnings. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20230727194457.3152309-7-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index ca520f2b1820e..5e248c60f8877 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -7040,7 +7040,7 @@ static int __ufshcd_issue_tm_cmd(struct ufs_hba *hba, static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id, u8 tm_function, u8 *tm_response) { - struct utp_task_req_desc treq = { { 0 }, }; + struct utp_task_req_desc treq = { }; enum utp_ocs ocs_value; int err; @@ -7205,7 +7205,7 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, { int err; enum dev_cmd_type cmd_type = DEV_CMD_TYPE_QUERY; - struct utp_task_req_desc treq = { { 0 }, }; + struct utp_task_req_desc treq = { }; enum utp_ocs ocs_value; u8 tm_f = be32_to_cpu(req_upiu->header.dword_1) >> 16 & MASK_TM_FUNC; -- GitLab From 08108d31129a104b06628b3ac95af2af9f5e9e4c Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 27 Jul 2023 12:41:19 -0700 Subject: [PATCH 0629/3445] scsi: ufs: Improve type safety Assign names to the enumeration types for UPIU types. Use these enumeration types where appropriate. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20230727194457.3152309-8-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd-priv.h | 2 +- drivers/ufs/core/ufshcd.c | 9 ++++----- include/ufs/ufs.h | 4 ++-- include/ufs/ufshcd.h | 6 ------ 4 files changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index 4feccd5c1ba2e..f42d99ce5bf1e 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -93,7 +93,7 @@ int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd); int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, struct utp_upiu_req *req_upiu, struct utp_upiu_req *rsp_upiu, - int msgcode, + enum upiu_request_transaction msgcode, u8 *desc_buff, int *buff_len, enum query_opcode desc_op); diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 5e248c60f8877..19c210ef74f57 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -879,7 +879,7 @@ static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba) * * Return: UPIU type. */ -static inline int +static inline enum upiu_response_transaction ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr) { return be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24; @@ -3032,7 +3032,7 @@ ufshcd_check_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) static int ufshcd_dev_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) { - int resp; + enum upiu_response_transaction resp; int err = 0; hba->ufs_stats.last_hibern8_exit_tstamp = ktime_set(0, 0); @@ -5271,9 +5271,8 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, switch (ocs) { case OCS_SUCCESS: - result = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr); hba->ufs_stats.last_hibern8_exit_tstamp = ktime_set(0, 0); - switch (result) { + switch (ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr)) { case UPIU_TRANSACTION_RESPONSE: /* * get the response UPIU result to extract @@ -7199,7 +7198,7 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, struct utp_upiu_req *req_upiu, struct utp_upiu_req *rsp_upiu, - int msgcode, + enum upiu_request_transaction msgcode, u8 *desc_buff, int *buff_len, enum query_opcode desc_op) { diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h index 0fb733683953f..797bf033c19a1 100644 --- a/include/ufs/ufs.h +++ b/include/ufs/ufs.h @@ -78,7 +78,7 @@ enum { }; /* UTP UPIU Transaction Codes Initiator to Target */ -enum { +enum upiu_request_transaction { UPIU_TRANSACTION_NOP_OUT = 0x00, UPIU_TRANSACTION_COMMAND = 0x01, UPIU_TRANSACTION_DATA_OUT = 0x02, @@ -87,7 +87,7 @@ enum { }; /* UTP UPIU Transaction Codes Target to Initiator */ -enum { +enum upiu_response_transaction { UPIU_TRANSACTION_NOP_IN = 0x20, UPIU_TRANSACTION_RESPONSE = 0x21, UPIU_TRANSACTION_DATA_IN = 0x22, diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 67bd089e70bc4..2b1f4f2a4464a 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -1357,12 +1357,6 @@ int ufshcd_get_vreg(struct device *dev, struct ufs_vreg *vreg); int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd); -int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, - struct utp_upiu_req *req_upiu, - struct utp_upiu_req *rsp_upiu, - int msgcode, - u8 *desc_buff, int *buff_len, - enum query_opcode desc_op); int ufshcd_advanced_rpmb_req_handler(struct ufs_hba *hba, struct utp_upiu_req *req_upiu, struct utp_upiu_req *rsp_upiu, struct ufs_ehs *ehs_req, struct ufs_ehs *ehs_rsp, int sg_cnt, -- GitLab From e8b0234f8458fc26a39d5d2b75f9637d9839e6b6 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 27 Jul 2023 12:41:20 -0700 Subject: [PATCH 0630/3445] scsi: ufs: Remove a local variable from ufshcd_abort_all() No functionality is changed. This patch prepares for unifying the MCQ and legacy code paths in this function. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20230727194457.3152309-9-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 19c210ef74f57..c0031cf8855c4 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -6387,9 +6387,14 @@ static bool ufshcd_is_pwr_mode_restore_needed(struct ufs_hba *hba) return false; } +/** + * ufshcd_abort_all - Abort all pending commands. + * @hba: Host bus adapter pointer. + * + * Return: true if and only if the host controller needs to be reset. + */ static bool ufshcd_abort_all(struct ufs_hba *hba) { - bool needs_reset = false; int tag, ret; if (is_mcq_enabled(hba)) { @@ -6404,10 +6409,8 @@ static bool ufshcd_abort_all(struct ufs_hba *hba) dev_err(hba->dev, "Aborting tag %d / CDB %#02x %s\n", tag, hba->lrb[tag].cmd ? hba->lrb[tag].cmd->cmnd[0] : -1, ret ? "failed" : "succeeded"); - if (ret) { - needs_reset = true; + if (ret) goto out; - } } } else { /* Clear pending transfer requests */ @@ -6416,25 +6419,22 @@ static bool ufshcd_abort_all(struct ufs_hba *hba) dev_err(hba->dev, "Aborting tag %d / CDB %#02x %s\n", tag, hba->lrb[tag].cmd ? hba->lrb[tag].cmd->cmnd[0] : -1, ret ? "failed" : "succeeded"); - if (ret) { - needs_reset = true; + if (ret) goto out; - } } } /* Clear pending task management requests */ for_each_set_bit(tag, &hba->outstanding_tasks, hba->nutmrs) { - if (ufshcd_clear_tm_cmd(hba, tag)) { - needs_reset = true; + ret = ufshcd_clear_tm_cmd(hba, tag); + if (ret) goto out; - } } out: /* Complete the requests that are cleared by s/w */ ufshcd_complete_requests(hba, false); - return needs_reset; + return ret != 0; } /** -- GitLab From f9c028e7415a5ba4c00c08b7951bca4239823597 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 27 Jul 2023 12:41:21 -0700 Subject: [PATCH 0631/3445] scsi: ufs: Simplify ufshcd_abort_all() Unify the MCQ and legacy code paths. This patch reworks code introduced by commit ab248643d3d6 ("scsi: ufs: core: Add error handling for MCQ mode"). Cc: "Bao D. Nguyen" Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20230727194457.3152309-10-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 46 +++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index c0031cf8855c4..bf76ea59ba6c7 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -6387,6 +6387,22 @@ static bool ufshcd_is_pwr_mode_restore_needed(struct ufs_hba *hba) return false; } +static bool ufshcd_abort_one(struct request *rq, void *priv) +{ + int *ret = priv; + u32 tag = rq->tag; + struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq); + struct scsi_device *sdev = cmd->device; + struct Scsi_Host *shost = sdev->host; + struct ufs_hba *hba = shost_priv(shost); + + *ret = ufshcd_try_to_abort_task(hba, tag); + dev_err(hba->dev, "Aborting tag %d / CDB %#02x %s\n", tag, + hba->lrb[tag].cmd ? hba->lrb[tag].cmd->cmnd[0] : -1, + *ret ? "failed" : "succeeded"); + return *ret == 0; +} + /** * ufshcd_abort_all - Abort all pending commands. * @hba: Host bus adapter pointer. @@ -6395,34 +6411,12 @@ static bool ufshcd_is_pwr_mode_restore_needed(struct ufs_hba *hba) */ static bool ufshcd_abort_all(struct ufs_hba *hba) { - int tag, ret; + int tag, ret = 0; - if (is_mcq_enabled(hba)) { - struct ufshcd_lrb *lrbp; - int tag; + blk_mq_tagset_busy_iter(&hba->host->tag_set, ufshcd_abort_one, &ret); + if (ret) + goto out; - for (tag = 0; tag < hba->nutrs; tag++) { - lrbp = &hba->lrb[tag]; - if (!ufshcd_cmd_inflight(lrbp->cmd)) - continue; - ret = ufshcd_try_to_abort_task(hba, tag); - dev_err(hba->dev, "Aborting tag %d / CDB %#02x %s\n", tag, - hba->lrb[tag].cmd ? hba->lrb[tag].cmd->cmnd[0] : -1, - ret ? "failed" : "succeeded"); - if (ret) - goto out; - } - } else { - /* Clear pending transfer requests */ - for_each_set_bit(tag, &hba->outstanding_reqs, hba->nutrs) { - ret = ufshcd_try_to_abort_task(hba, tag); - dev_err(hba->dev, "Aborting tag %d / CDB %#02x %s\n", tag, - hba->lrb[tag].cmd ? hba->lrb[tag].cmd->cmnd[0] : -1, - ret ? "failed" : "succeeded"); - if (ret) - goto out; - } - } /* Clear pending task management requests */ for_each_set_bit(tag, &hba->outstanding_tasks, hba->nutmrs) { ret = ufshcd_clear_tm_cmd(hba, tag); -- GitLab From e2566e0b7937f0a0b84f8b662fceebac6a1386c7 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 27 Jul 2023 12:41:22 -0700 Subject: [PATCH 0632/3445] scsi: ufs: Remove a member variable Remove the 'response' member variable because no code reads its value. Additionally, move the ufs_query_req and ufs_query_res data structure definitions into include/ufs/ufshcd.h because these data structures are related to the UFS host controller driver. Reviewed-by: Avri Altman Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20230727194457.3152309-11-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 6 +----- include/ufs/ufs.h | 20 -------------------- include/ufs/ufshcd.h | 19 +++++++++++++++++++ 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index bf76ea59ba6c7..4348b0dfde29f 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -3014,12 +3014,8 @@ static int ufshcd_clear_cmd(struct ufs_hba *hba, u32 task_tag) static int ufshcd_check_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) { - struct ufs_query_res *query_res = &hba->dev_cmd.query.response; - - /* Get the UPIU response */ - query_res->response = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr) >> + return ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr) >> UPIU_RSP_CODE_OFFSET; - return query_res->response; } /** diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h index 797bf033c19a1..0ee1fdf2fe836 100644 --- a/include/ufs/ufs.h +++ b/include/ufs/ufs.h @@ -537,26 +537,6 @@ struct utp_upiu_rsp { }; }; -/** - * struct ufs_query_req - parameters for building a query request - * @query_func: UPIU header query function - * @upiu_req: the query request data - */ -struct ufs_query_req { - u8 query_func; - struct utp_upiu_query upiu_req; -}; - -/** - * struct ufs_query_resp - UPIU QUERY - * @response: device response code - * @upiu_res: query response data - */ -struct ufs_query_res { - u8 response; - struct utp_upiu_query upiu_res; -}; - /* * VCCQ & VCCQ2 current requirement when UFS device is in sleep state * and link is in Hibern8 state. diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 2b1f4f2a4464a..bf4070a4b95f1 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -202,6 +202,25 @@ struct ufshcd_lrb { bool req_abort_skip; }; +/** + * struct ufs_query_req - parameters for building a query request + * @query_func: UPIU header query function + * @upiu_req: the query request data + */ +struct ufs_query_req { + u8 query_func; + struct utp_upiu_query upiu_req; +}; + +/** + * struct ufs_query_resp - UPIU QUERY + * @response: device response code + * @upiu_res: query response data + */ +struct ufs_query_res { + struct utp_upiu_query upiu_res; +}; + /** * struct ufs_query - holds relevant data structures for query request * @request: request upiu and function -- GitLab From 67a2a8973832cbeb23a5c04a1dda94da71490a0d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 27 Jul 2023 12:41:23 -0700 Subject: [PATCH 0633/3445] scsi: ufs: Simplify transfer request header initialization Make the code that initializes UTP transfer request headers easier to read by using bitfields instead of __le32 where appropriate. Cc: "Bao D. Nguyen" Cc: Eric Biggers Cc: Avri Altman Cc: Bean Huo Cc: Adrian Hunter Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20230727194457.3152309-12-bvanassche@acm.org Reviewed-by: Avri Altman Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-mcq.c | 7 +-- drivers/ufs/core/ufshcd-crypto.h | 20 ++++----- drivers/ufs/core/ufshcd.c | 77 ++++++++++++++++++++++---------- include/ufs/ufs.h | 3 -- include/ufs/ufshci.h | 50 ++++++++++++++------- 5 files changed, 99 insertions(+), 58 deletions(-) diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index a3d4ef8aa3b92..66a4e24484a30 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -558,12 +558,7 @@ unlock: */ static void ufshcd_mcq_nullify_sqe(struct utp_transfer_req_desc *utrd) { - u32 dword_0; - - dword_0 = le32_to_cpu(utrd->header.dword_0); - dword_0 &= ~UPIU_COMMAND_TYPE_MASK; - dword_0 |= FIELD_PREP(UPIU_COMMAND_TYPE_MASK, 0xF); - utrd->header.dword_0 = cpu_to_le32(dword_0); + utrd->header.command_type = 0xf; } /** diff --git a/drivers/ufs/core/ufshcd-crypto.h b/drivers/ufs/core/ufshcd-crypto.h index 504cc841540b2..be8596f20ba2f 100644 --- a/drivers/ufs/core/ufshcd-crypto.h +++ b/drivers/ufs/core/ufshcd-crypto.h @@ -26,15 +26,15 @@ static inline void ufshcd_prepare_lrbp_crypto(struct request *rq, } static inline void -ufshcd_prepare_req_desc_hdr_crypto(struct ufshcd_lrb *lrbp, u32 *dword_0, - u32 *dword_1, u32 *dword_3) +ufshcd_prepare_req_desc_hdr_crypto(struct ufshcd_lrb *lrbp, + struct request_desc_header *h) { - if (lrbp->crypto_key_slot >= 0) { - *dword_0 |= UTP_REQ_DESC_CRYPTO_ENABLE_CMD; - *dword_0 |= lrbp->crypto_key_slot; - *dword_1 = lower_32_bits(lrbp->data_unit_num); - *dword_3 = upper_32_bits(lrbp->data_unit_num); - } + if (lrbp->crypto_key_slot < 0) + return; + h->enable_crypto = 1; + h->cci = lrbp->crypto_key_slot; + h->dunl = cpu_to_le32(lower_32_bits(lrbp->data_unit_num)); + h->dunu = cpu_to_le32(upper_32_bits(lrbp->data_unit_num)); } bool ufshcd_crypto_enable(struct ufs_hba *hba); @@ -51,8 +51,8 @@ static inline void ufshcd_prepare_lrbp_crypto(struct request *rq, struct ufshcd_lrb *lrbp) { } static inline void -ufshcd_prepare_req_desc_hdr_crypto(struct ufshcd_lrb *lrbp, u32 *dword_0, - u32 *dword_1, u32 *dword_3) { } +ufshcd_prepare_req_desc_hdr_crypto(struct ufshcd_lrb *lrbp, + struct request_desc_header *h) { } static inline bool ufshcd_crypto_enable(struct ufs_hba *hba) { diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 4348b0dfde29f..b85c7a28fff5e 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -794,7 +794,7 @@ static enum utp_ocs ufshcd_get_tr_ocs(struct ufshcd_lrb *lrbp, if (cqe) return le32_to_cpu(cqe->status) & MASK_OCS; - return le32_to_cpu(lrbp->utr_descriptor_ptr->header.dword_2) & MASK_OCS; + return lrbp->utr_descriptor_ptr->header.ocs & MASK_OCS; } /** @@ -2587,10 +2587,10 @@ static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp, u8 *upiu_flags, enum dma_data_direction cmd_dir, int ehs_length) { struct utp_transfer_req_desc *req_desc = lrbp->utr_descriptor_ptr; - u32 data_direction; - u32 dword_0; - u32 dword_1 = 0; - u32 dword_3 = 0; + struct request_desc_header *h = &req_desc->header; + enum utp_data_direction data_direction; + + *h = (typeof(*h)){ }; if (cmd_dir == DMA_FROM_DEVICE) { data_direction = UTP_DEVICE_TO_HOST; @@ -2603,25 +2603,22 @@ static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp, u8 *upiu_flags, *upiu_flags = UPIU_CMD_FLAGS_NONE; } - dword_0 = data_direction | (lrbp->command_type << UPIU_COMMAND_TYPE_OFFSET) | - ehs_length << 8; + h->command_type = lrbp->command_type; + h->data_direction = data_direction; + h->ehs_length = ehs_length; + if (lrbp->intr_cmd) - dword_0 |= UTP_REQ_DESC_INT_CMD; + h->interrupt = 1; /* Prepare crypto related dwords */ - ufshcd_prepare_req_desc_hdr_crypto(lrbp, &dword_0, &dword_1, &dword_3); + ufshcd_prepare_req_desc_hdr_crypto(lrbp, h); - /* Transfer request descriptor header fields */ - req_desc->header.dword_0 = cpu_to_le32(dword_0); - req_desc->header.dword_1 = cpu_to_le32(dword_1); /* * assigning invalid value for command status. Controller * updates OCS on command completion, with the command * status */ - req_desc->header.dword_2 = - cpu_to_le32(OCS_INVALID_COMMAND_STATUS); - req_desc->header.dword_3 = cpu_to_le32(dword_3); + h->ocs = OCS_INVALID_COMMAND_STATUS; req_desc->prd_table_length = 0; } @@ -5445,8 +5442,7 @@ void ufshcd_compl_one_cqe(struct ufs_hba *hba, int task_tag, if (hba->dev_cmd.complete) { if (cqe) { ocs = le32_to_cpu(cqe->status) & MASK_OCS; - lrbp->utr_descriptor_ptr->header.dword_2 = - cpu_to_le32(ocs); + lrbp->utr_descriptor_ptr->header.ocs = ocs; } complete(hba->dev_cmd.complete); ufshcd_clk_scaling_update_busy(hba); @@ -7034,8 +7030,8 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id, int err; /* Configure task request descriptor */ - treq.header.dword_0 = cpu_to_le32(UTP_REQ_DESC_INT_CMD); - treq.header.dword_2 = cpu_to_le32(OCS_INVALID_COMMAND_STATUS); + treq.header.interrupt = 1; + treq.header.ocs = OCS_INVALID_COMMAND_STATUS; /* Configure task request UPIU */ treq.upiu_req.req_header.dword_0 = cpu_to_be32(lun_id << 8) | @@ -7053,7 +7049,7 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id, if (err == -ETIMEDOUT) return err; - ocs_value = le32_to_cpu(treq.header.dword_2) & MASK_OCS; + ocs_value = treq.header.ocs & MASK_OCS; if (ocs_value != OCS_SUCCESS) dev_err(hba->dev, "%s: failed, ocs = 0x%x\n", __func__, ocs_value); @@ -7213,8 +7209,8 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, break; case UPIU_TRANSACTION_TASK_REQ: - treq.header.dword_0 = cpu_to_le32(UTP_REQ_DESC_INT_CMD); - treq.header.dword_2 = cpu_to_le32(OCS_INVALID_COMMAND_STATUS); + treq.header.interrupt = 1; + treq.header.ocs = OCS_INVALID_COMMAND_STATUS; memcpy(&treq.upiu_req, req_upiu, sizeof(*req_upiu)); @@ -7222,7 +7218,7 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, if (err == -ETIMEDOUT) break; - ocs_value = le32_to_cpu(treq.header.dword_2) & MASK_OCS; + ocs_value = treq.header.ocs & MASK_OCS; if (ocs_value != OCS_SUCCESS) { dev_err(hba->dev, "%s: failed, ocs = 0x%x\n", __func__, ocs_value); @@ -10567,6 +10563,39 @@ static const struct dev_pm_ops ufshcd_wl_pm_ops = { SET_RUNTIME_PM_OPS(ufshcd_wl_runtime_suspend, ufshcd_wl_runtime_resume, NULL) }; +static void ufshcd_check_header_layout(void) +{ + BUILD_BUG_ON(((u8 *)&(struct request_desc_header){ + .cci = 3})[0] != 3); + + BUILD_BUG_ON(((u8 *)&(struct request_desc_header){ + .ehs_length = 2})[1] != 2); + + BUILD_BUG_ON(((u8 *)&(struct request_desc_header){ + .enable_crypto = 1})[2] + != 0x80); + + BUILD_BUG_ON((((u8 *)&(struct request_desc_header){ + .command_type = 5, + .data_direction = 3, + .interrupt = 1, + })[3]) != ((5 << 4) | (3 << 1) | 1)); + + BUILD_BUG_ON(((__le32 *)&(struct request_desc_header){ + .dunl = cpu_to_le32(0xdeadbeef)})[1] != + cpu_to_le32(0xdeadbeef)); + + BUILD_BUG_ON(((u8 *)&(struct request_desc_header){ + .ocs = 4})[8] != 4); + + BUILD_BUG_ON(((u8 *)&(struct request_desc_header){ + .cds = 5})[9] != 5); + + BUILD_BUG_ON(((__le32 *)&(struct request_desc_header){ + .dunu = cpu_to_le32(0xbadcafe)})[3] != + cpu_to_le32(0xbadcafe)); +} + /* * ufs_dev_wlun_template - describes ufs device wlun * ufs-device wlun - used to send pm commands @@ -10592,6 +10621,8 @@ static int __init ufshcd_core_init(void) { int ret; + ufshcd_check_header_layout(); + ufs_debugfs_init(); ret = scsi_register_driver(&ufs_dev_wlun_template.gendrv); diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h index 0ee1fdf2fe836..80fae94848070 100644 --- a/include/ufs/ufs.h +++ b/include/ufs/ufs.h @@ -473,9 +473,6 @@ enum { UPIU_COMMAND_SET_TYPE_QUERY = 0x2, }; -/* UTP Transfer Request Command Offset */ -#define UPIU_COMMAND_TYPE_OFFSET 28 - /* Offset of the response code in the UPIU header */ #define UPIU_RSP_CODE_OFFSET 8 diff --git a/include/ufs/ufshci.h b/include/ufs/ufshci.h index c48135554d5cb..d5accacae6bca 100644 --- a/include/ufs/ufshci.h +++ b/include/ufs/ufshci.h @@ -127,7 +127,6 @@ enum { }; #define SQ_ICU_ERR_CODE_MASK GENMASK(7, 4) -#define UPIU_COMMAND_TYPE_MASK GENMASK(31, 28) #define UFS_MASK(mask, offset) ((mask) << (offset)) /* UFS Version 08h */ @@ -439,15 +438,13 @@ enum { UTP_SCSI_COMMAND = 0x00000000, UTP_NATIVE_UFS_COMMAND = 0x10000000, UTP_DEVICE_MANAGEMENT_FUNCTION = 0x20000000, - UTP_REQ_DESC_INT_CMD = 0x01000000, - UTP_REQ_DESC_CRYPTO_ENABLE_CMD = 0x00800000, }; /* UTP Transfer Request Data Direction (DD) */ -enum { - UTP_NO_DATA_TRANSFER = 0x00000000, - UTP_HOST_TO_DEVICE = 0x02000000, - UTP_DEVICE_TO_HOST = 0x04000000, +enum utp_data_direction { + UTP_NO_DATA_TRANSFER = 0, + UTP_HOST_TO_DEVICE = 1, + UTP_DEVICE_TO_HOST = 2, }; /* Overall command status values */ @@ -506,17 +503,38 @@ struct utp_transfer_cmd_desc { /** * struct request_desc_header - Descriptor Header common to both UTRD and UTMRD - * @dword0: Descriptor Header DW0 - * @dword1: Descriptor Header DW1 - * @dword2: Descriptor Header DW2 - * @dword3: Descriptor Header DW3 */ struct request_desc_header { - __le32 dword_0; - __le32 dword_1; - __le32 dword_2; - __le32 dword_3; -}; + u8 cci; + u8 ehs_length; +#if defined(__BIG_ENDIAN) + u8 enable_crypto:1; + u8 reserved2:7; + + u8 command_type:4; + u8 reserved1:1; + u8 data_direction:2; + u8 interrupt:1; +#elif defined(__LITTLE_ENDIAN) + u8 reserved2:7; + u8 enable_crypto:1; + + u8 interrupt:1; + u8 data_direction:2; + u8 reserved1:1; + u8 command_type:4; +#else +#error +#endif + + __le32 dunl; + u8 ocs; + u8 cds; + __le16 ldbc; + __le32 dunu; +}; + +static_assert(sizeof(struct request_desc_header) == 16); /** * struct utp_transfer_req_desc - UTP Transfer Request Descriptor (UTRD) -- GitLab From 617bfaa8dd50d6a3ffc8694b4696bf2aa196bd44 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 27 Jul 2023 12:41:24 -0700 Subject: [PATCH 0634/3445] scsi: ufs: Simplify response header parsing Make the code that parses UTP transfer request headers easier to read by using u8 instead of __be32 where appropriate. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20230727194457.3152309-13-bvanassche@acm.org Reviewed-by: Avri Altman Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 153 ++++++++++++------------------- include/uapi/scsi/scsi_bsg_ufs.h | 52 ++++++++++- include/ufs/ufs.h | 18 ++-- 3 files changed, 115 insertions(+), 108 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index b85c7a28fff5e..2e669e64872cf 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -882,35 +882,7 @@ static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba) static inline enum upiu_response_transaction ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr) { - return be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24; -} - -/** - * ufshcd_get_rsp_upiu_result - Get the result from response UPIU - * @ucd_rsp_ptr: pointer to response UPIU - * - * This function gets the response status and scsi_status from response UPIU - * - * Return: the response result code. - */ -static inline int -ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp *ucd_rsp_ptr) -{ - return be32_to_cpu(ucd_rsp_ptr->header.dword_1) & MASK_RSP_UPIU_RESULT; -} - -/* - * ufshcd_get_rsp_upiu_data_seg_len - Get the data segment length - * from response UPIU - * @ucd_rsp_ptr: pointer to response UPIU - * - * Return: the data segment length. - */ -static inline unsigned int -ufshcd_get_rsp_upiu_data_seg_len(struct utp_upiu_rsp *ucd_rsp_ptr) -{ - return be32_to_cpu(ucd_rsp_ptr->header.dword_2) & - MASK_RSP_UPIU_DATA_SEG_LEN; + return ucd_rsp_ptr->header.transaction_code; } /** @@ -924,8 +896,7 @@ ufshcd_get_rsp_upiu_data_seg_len(struct utp_upiu_rsp *ucd_rsp_ptr) */ static inline bool ufshcd_is_exception_event(struct utp_upiu_rsp *ucd_rsp_ptr) { - return be32_to_cpu(ucd_rsp_ptr->header.dword_2) & - MASK_RSP_EXCEPTION_EVENT; + return ucd_rsp_ptr->header.device_information & 1; } /** @@ -2224,10 +2195,11 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag, static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp) { u8 *const sense_buffer = lrbp->cmd->sense_buffer; + u16 resp_len; int len; - if (sense_buffer && - ufshcd_get_rsp_upiu_data_seg_len(lrbp->ucd_rsp_ptr)) { + resp_len = be16_to_cpu(lrbp->ucd_rsp_ptr->header.data_segment_length); + if (sense_buffer && resp_len) { int len_to_copy; len = be16_to_cpu(lrbp->ucd_rsp_ptr->sr.sense_data_len); @@ -2262,8 +2234,8 @@ int ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) u16 buf_len; /* data segment length */ - resp_len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) & - MASK_QUERY_DATA_SEG_LEN; + resp_len = be16_to_cpu(lrbp->ucd_rsp_ptr->header + .data_segment_length); buf_len = be16_to_cpu( hba->dev_cmd.query.request.upiu_req.length); if (likely(buf_len >= resp_len)) { @@ -2636,15 +2608,13 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u8 upiu_flags) struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr; unsigned short cdb_len; - /* command descriptor fields */ - ucd_req_ptr->header.dword_0 = upiu_header_dword( - UPIU_TRANSACTION_COMMAND, upiu_flags, - lrbp->lun, lrbp->task_tag); - ucd_req_ptr->header.dword_1 = upiu_header_dword( - UPIU_COMMAND_SET_TYPE_SCSI, 0, 0, 0); - - /* Total EHS length and Data segment length will be zero */ - ucd_req_ptr->header.dword_2 = 0; + ucd_req_ptr->header = (struct utp_upiu_header){ + .transaction_code = UPIU_TRANSACTION_COMMAND, + .flags = upiu_flags, + .lun = lrbp->lun, + .task_tag = lrbp->task_tag, + .command_set_type = UPIU_COMMAND_SET_TYPE_SCSI, + }; ucd_req_ptr->sc.exp_data_transfer_len = cpu_to_be32(cmd->sdb.length); @@ -2669,18 +2639,19 @@ static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, u16 len = be16_to_cpu(query->request.upiu_req.length); /* Query request header */ - ucd_req_ptr->header.dword_0 = upiu_header_dword( - UPIU_TRANSACTION_QUERY_REQ, upiu_flags, - lrbp->lun, lrbp->task_tag); - ucd_req_ptr->header.dword_1 = upiu_header_dword( - 0, query->request.query_func, 0, 0); - - /* Data segment length only need for WRITE_DESC */ - if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) - ucd_req_ptr->header.dword_2 = - upiu_header_dword(0, 0, len >> 8, (u8)len); - else - ucd_req_ptr->header.dword_2 = 0; + ucd_req_ptr->header = (struct utp_upiu_header){ + .transaction_code = UPIU_TRANSACTION_QUERY_REQ, + .flags = upiu_flags, + .lun = lrbp->lun, + .task_tag = lrbp->task_tag, + .query_function = query->request.query_func, + /* Data segment length only need for WRITE_DESC */ + .data_segment_length = + query->request.upiu_req.opcode == + UPIU_QUERY_OPCODE_WRITE_DESC ? + cpu_to_be16(len) : + 0, + }; /* Copy the Query Request buffer as is */ memcpy(&ucd_req_ptr->qr, &query->request.upiu_req, @@ -2699,12 +2670,10 @@ static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp) memset(ucd_req_ptr, 0, sizeof(struct utp_upiu_req)); - /* command descriptor fields */ - ucd_req_ptr->header.dword_0 = upiu_header_dword( - UPIU_TRANSACTION_NOP_OUT, 0, 0, lrbp->task_tag); - /* clear rest of the fields of basic header */ - ucd_req_ptr->header.dword_1 = 0; - ucd_req_ptr->header.dword_2 = 0; + ucd_req_ptr->header = (struct utp_upiu_header){ + .transaction_code = UPIU_TRANSACTION_NOP_OUT, + .task_tag = lrbp->task_tag, + }; memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); } @@ -3008,13 +2977,6 @@ static int ufshcd_clear_cmd(struct ufs_hba *hba, u32 task_tag) mask, ~mask, 1000, 1000); } -static int -ufshcd_check_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) -{ - return ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr) >> - UPIU_RSP_CODE_OFFSET; -} - /** * ufshcd_dev_cmd_completion() - handles device management command responses * @hba: per adapter instance @@ -3039,11 +3001,13 @@ ufshcd_dev_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) __func__, resp); } break; - case UPIU_TRANSACTION_QUERY_RSP: - err = ufshcd_check_query_response(hba, lrbp); - if (!err) + case UPIU_TRANSACTION_QUERY_RSP: { + u8 response = lrbp->ucd_rsp_ptr->header.response; + + if (response == 0) err = ufshcd_copy_query_response(hba, lrbp); break; + } case UPIU_TRANSACTION_REJECT_UPIU: /* TODO: handle Reject UPIU Response */ err = -EPERM; @@ -5244,7 +5208,7 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, u8 upiu_flags; u32 resid; - upiu_flags = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_0) >> 16; + upiu_flags = lrbp->ucd_rsp_ptr->header.flags; resid = be32_to_cpu(lrbp->ucd_rsp_ptr->sr.residual_transfer_count); /* * Test !overflow instead of underflow to support UFS devices that do @@ -5257,8 +5221,8 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, ocs = ufshcd_get_tr_ocs(lrbp, cqe); if (hba->quirks & UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR) { - if (be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_1) & - MASK_RSP_UPIU_RESULT) + if (lrbp->ucd_rsp_ptr->header.response || + lrbp->ucd_rsp_ptr->header.status) ocs = OCS_SUCCESS; } @@ -5267,17 +5231,11 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, hba->ufs_stats.last_hibern8_exit_tstamp = ktime_set(0, 0); switch (ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr)) { case UPIU_TRANSACTION_RESPONSE: - /* - * get the response UPIU result to extract - * the SCSI command status - */ - result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr); - /* * get the result based on SCSI status response * to notify the SCSI midlayer of the command status */ - scsi_status = result & MASK_SCSI_STATUS; + scsi_status = lrbp->ucd_rsp_ptr->header.status; result = ufshcd_scsi_cmd_status(lrbp, scsi_status); /* @@ -6967,7 +6925,7 @@ static int __ufshcd_issue_tm_cmd(struct ufs_hba *hba, WARN_ONCE(task_tag < 0 || task_tag >= hba->nutmrs, "Invalid tag %d\n", task_tag); hba->tmf_rqs[req->tag] = req; - treq->upiu_req.req_header.dword_0 |= cpu_to_be32(task_tag); + treq->upiu_req.req_header.task_tag = task_tag; memcpy(hba->utmrdl_base_addr + task_tag, treq, sizeof(*treq)); ufshcd_vops_setup_task_mgmt(hba, task_tag, tm_function); @@ -7034,9 +6992,9 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id, treq.header.ocs = OCS_INVALID_COMMAND_STATUS; /* Configure task request UPIU */ - treq.upiu_req.req_header.dword_0 = cpu_to_be32(lun_id << 8) | - cpu_to_be32(UPIU_TRANSACTION_TASK_REQ << 24); - treq.upiu_req.req_header.dword_1 = cpu_to_be32(tm_function << 16); + treq.upiu_req.req_header.transaction_code = UPIU_TRANSACTION_TASK_REQ; + treq.upiu_req.req_header.lun = lun_id; + treq.upiu_req.req_header.tm_function = tm_function; /* * The host shall provide the same value for LUN field in the basic @@ -7110,7 +7068,7 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE; /* update the task tag in the request upiu */ - req_upiu->header.dword_0 |= cpu_to_be32(tag); + req_upiu->header.task_tag = tag; ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE, 0); @@ -7143,8 +7101,8 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, memcpy(rsp_upiu, lrbp->ucd_rsp_ptr, sizeof(*rsp_upiu)); if (desc_buff && desc_op == UPIU_QUERY_OPCODE_READ_DESC) { u8 *descp = (u8 *)lrbp->ucd_rsp_ptr + sizeof(*rsp_upiu); - u16 resp_len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) & - MASK_QUERY_DATA_SEG_LEN; + u16 resp_len = be16_to_cpu(lrbp->ucd_rsp_ptr->header + .data_segment_length); if (*buff_len >= resp_len) { memcpy(desc_buff, descp, resp_len); @@ -7192,7 +7150,7 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, enum dev_cmd_type cmd_type = DEV_CMD_TYPE_QUERY; struct utp_task_req_desc treq = { }; enum utp_ocs ocs_value; - u8 tm_f = be32_to_cpu(req_upiu->header.dword_1) >> 16 & MASK_TM_FUNC; + u8 tm_f = req_upiu->header.tm_function; switch (msgcode) { case UPIU_TRANSACTION_NOP_OUT: @@ -7284,7 +7242,9 @@ int ufshcd_advanced_rpmb_req_handler(struct ufs_hba *hba, struct utp_upiu_req *r ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, dir, 2); /* update the task tag and LUN in the request upiu */ - req_upiu->header.dword_0 |= cpu_to_be32(upiu_flags << 16 | UFS_UPIU_RPMB_WLUN << 8 | tag); + req_upiu->header.flags = upiu_flags; + req_upiu->header.lun = UFS_UPIU_RPMB_WLUN; + req_upiu->header.task_tag = tag; /* copy the UPIU(contains CDB) request as it is */ memcpy(lrbp->ucd_req_ptr, req_upiu, sizeof(*lrbp->ucd_req_ptr)); @@ -7306,9 +7266,10 @@ int ufshcd_advanced_rpmb_req_handler(struct ufs_hba *hba, struct utp_upiu_req *r /* Just copy the upiu response as it is */ memcpy(rsp_upiu, lrbp->ucd_rsp_ptr, sizeof(*rsp_upiu)); /* Get the response UPIU result */ - result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr); + result = (lrbp->ucd_rsp_ptr->header.response << 8) | + lrbp->ucd_rsp_ptr->header.status; - ehs_len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) >> 24; + ehs_len = lrbp->ucd_rsp_ptr->header.ehs_length; /* * Since the bLength in EHS indicates the total size of the EHS Header and EHS Data * in 32 Byte units, the value of the bLength Request/Response for Advanced RPMB @@ -10594,6 +10555,12 @@ static void ufshcd_check_header_layout(void) BUILD_BUG_ON(((__le32 *)&(struct request_desc_header){ .dunu = cpu_to_le32(0xbadcafe)})[3] != cpu_to_le32(0xbadcafe)); + + BUILD_BUG_ON(((u8 *)&(struct utp_upiu_header){ + .iid = 0xf })[4] != 0xf0); + + BUILD_BUG_ON(((u8 *)&(struct utp_upiu_header){ + .command_set_type = 0xf })[4] != 0xf); } /* diff --git a/include/uapi/scsi/scsi_bsg_ufs.h b/include/uapi/scsi/scsi_bsg_ufs.h index 2801b65299aa3..bf1832dc35db9 100644 --- a/include/uapi/scsi/scsi_bsg_ufs.h +++ b/include/uapi/scsi/scsi_bsg_ufs.h @@ -8,6 +8,7 @@ #ifndef SCSI_BSG_UFS_H #define SCSI_BSG_UFS_H +#include #include /* * This file intended to be included by both kernel and user space @@ -40,11 +41,56 @@ enum ufs_rpmb_op_type { * @dword_0: UPIU header DW-0 * @dword_1: UPIU header DW-1 * @dword_2: UPIU header DW-2 + * + * @transaction_code: Type of request or response. See also enum + * upiu_request_transaction and enum upiu_response_transaction. + * @flags: UPIU flags. The meaning of individual flags depends on the + * transaction code. + * @lun: Logical unit number. + * @task_tag: Task tag. + * @iid: Initiator ID. + * @command_set_type: 0 for SCSI command set; 1 for UFS specific. + * @tm_function: Task management function in case of a task management request + * UPIU. + * @query_function: Query function in case of a query request UPIU. + * @response: 0 for success; 1 for failure. + * @status: SCSI status if this is the header of a response to a SCSI command. + * @ehs_length: EHS length in units of 32 bytes. + * @device_information: + * @data_segment_length: data segment length. */ struct utp_upiu_header { - __be32 dword_0; - __be32 dword_1; - __be32 dword_2; + union { + struct { + __be32 dword_0; + __be32 dword_1; + __be32 dword_2; + }; + struct { + __u8 transaction_code; + __u8 flags; + __u8 lun; + __u8 task_tag; +#if defined(__BIG_ENDIAN) + __u8 iid: 4; + __u8 command_set_type: 4; +#elif defined(__LITTLE_ENDIAN) + __u8 command_set_type: 4; + __u8 iid: 4; +#else +#error +#endif + union { + __u8 tm_function; + __u8 query_function; + }; + __u8 response; + __u8 status; + __u8 ehs_length; + __u8 device_information; + __be16 data_segment_length; + }; + }; }; /** diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h index 80fae94848070..3ebb677d993ac 100644 --- a/include/ufs/ufs.h +++ b/include/ufs/ufs.h @@ -15,6 +15,12 @@ #include #include +/* + * Using static_assert() is not allowed in UAPI header files. Hence the check + * in this header file of the size of struct utp_upiu_header. + */ +static_assert(sizeof(struct utp_upiu_header) == 12); + #define GENERAL_UPIU_REQUEST_SIZE (sizeof(struct utp_upiu_req)) #define QUERY_DESC_MAX_SIZE 255 #define QUERY_DESC_MIN_SIZE 2 @@ -23,11 +29,6 @@ (sizeof(struct utp_upiu_header))) #define UFS_SENSE_SIZE 18 -static inline __be32 upiu_header_dword(u8 byte3, u8 byte2, u8 byte1, u8 byte0) -{ - return cpu_to_be32(byte3 << 24 | byte2 << 16 | byte1 << 8 | byte0); -} - /* * UFS device may have standard LUs and LUN id could be from 0x00 to * 0x7F. Standard LUs use "Peripheral Device Addressing Format". @@ -477,14 +478,7 @@ enum { #define UPIU_RSP_CODE_OFFSET 8 enum { - MASK_SCSI_STATUS = 0xFF, - MASK_TASK_RESPONSE = 0xFF00, - MASK_RSP_UPIU_RESULT = 0xFFFF, - MASK_QUERY_DATA_SEG_LEN = 0xFFFF, - MASK_RSP_UPIU_DATA_SEG_LEN = 0xFFFF, - MASK_RSP_EXCEPTION_EVENT = 0x10000, MASK_TM_SERVICE_RESP = 0xFF, - MASK_TM_FUNC = 0xFF, }; /* Task management service response */ -- GitLab From 1d6664fadda3e028b8220ba1ba487a928e801825 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Sun, 25 Jun 2023 15:34:38 +0800 Subject: [PATCH 0635/3445] KVM: x86: Use sysfs_emit() instead of sprintf() Use sysfs_emit() instead of the sprintf() for sysfs entries. sysfs_emit() knows the maximum of the temporary buffer used for outputting sysfs content and avoids overrunning the buffer length. Signed-off-by: Like Xu Link: https://lore.kernel.org/r/20230625073438.57427-1-likexu@tencent.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/mmu/mmu.c | 2 +- arch/x86/kvm/vmx/vmx.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index ec169f5c7dce2..31d9cbe817a26 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -6862,7 +6862,7 @@ static void mmu_destroy_caches(void) static int get_nx_huge_pages(char *buffer, const struct kernel_param *kp) { if (nx_hugepage_mitigation_hard_disabled) - return sprintf(buffer, "never\n"); + return sysfs_emit(buffer, "never\n"); return param_get_bool(buffer, kp); } diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 0ecf4be2c6af0..254f2296e5494 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -366,9 +366,9 @@ static int vmentry_l1d_flush_set(const char *s, const struct kernel_param *kp) static int vmentry_l1d_flush_get(char *s, const struct kernel_param *kp) { if (WARN_ON_ONCE(l1tf_vmx_mitigation >= ARRAY_SIZE(vmentry_l1d_param))) - return sprintf(s, "???\n"); + return sysfs_emit(s, "???\n"); - return sprintf(s, "%s\n", vmentry_l1d_param[l1tf_vmx_mitigation].option); + return sysfs_emit(s, "%s\n", vmentry_l1d_param[l1tf_vmx_mitigation].option); } static void vmx_setup_fb_clear_ctrl(void) -- GitLab From 1672730cffaf56ea3f7b697d499d9697a34b77f1 Mon Sep 17 00:00:00 2001 From: Dawei Li Date: Sun, 16 Jul 2023 00:16:21 +0800 Subject: [PATCH 0636/3445] iommu/arm-smmu-v3: Change vmid alloc strategy from bitmap to ida For current implementation of vmid allocation of arm smmu-v3, a per-smmu devide bitmap of 64K bits(8K bytes) is allocated on behalf of possible VMID range, which is two pages for some architectures. Besides that, its memory consumption is 'static', despite of how many VMIDs are allocated actually. That's memory inefficient and lack of scalability. So an IDA based implementation is introduced to address this issue, which is capable of self-expanding on the actual need of VMID allocation. Signed-off-by: Dawei Li Reviewed-by: Jason Gunthorpe Link: https://lore.kernel.org/r/TYCP286MB2323E0C525FF9F94E3B07C7ACA35A@TYCP286MB2323.JPNP286.PROD.OUTLOOK.COM Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 29 +++++---------------- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 2 +- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index 9b0dc35056019..d9487602701f3 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -2055,24 +2055,6 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type) return &smmu_domain->domain; } -static int arm_smmu_bitmap_alloc(unsigned long *map, int span) -{ - int idx, size = 1 << span; - - do { - idx = find_first_zero_bit(map, size); - if (idx == size) - return -ENOSPC; - } while (test_and_set_bit(idx, map)); - - return idx; -} - -static void arm_smmu_bitmap_free(unsigned long *map, int idx) -{ - clear_bit(idx, map); -} - static void arm_smmu_domain_free(struct iommu_domain *domain) { struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); @@ -2093,7 +2075,7 @@ static void arm_smmu_domain_free(struct iommu_domain *domain) } else { struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg; if (cfg->vmid) - arm_smmu_bitmap_free(smmu->vmid_map, cfg->vmid); + ida_free(&smmu->vmid_map, cfg->vmid); } kfree(smmu_domain); @@ -2167,7 +2149,9 @@ static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain, struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg; typeof(&pgtbl_cfg->arm_lpae_s2_cfg.vtcr) vtcr; - vmid = arm_smmu_bitmap_alloc(smmu->vmid_map, smmu->vmid_bits); + /* Reserve VMID 0 for stage-2 bypass STEs */ + vmid = ida_alloc_range(&smmu->vmid_map, 1, (1 << smmu->vmid_bits) - 1, + GFP_KERNEL); if (vmid < 0) return vmid; @@ -3098,8 +3082,8 @@ static int arm_smmu_init_strtab(struct arm_smmu_device *smmu) reg |= STRTAB_BASE_RA; smmu->strtab_cfg.strtab_base = reg; - /* Allocate the first VMID for stage-2 bypass STEs */ - set_bit(0, smmu->vmid_map); + ida_init(&smmu->vmid_map); + return 0; } @@ -3923,6 +3907,7 @@ static void arm_smmu_device_remove(struct platform_device *pdev) iommu_device_sysfs_remove(&smmu->iommu); arm_smmu_device_disable(smmu); iopf_queue_free(smmu->evtq.iopf); + ida_destroy(&smmu->vmid_map); } static void arm_smmu_device_shutdown(struct platform_device *pdev) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h index dcab85698a4e2..9915850dd4dbf 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h @@ -670,7 +670,7 @@ struct arm_smmu_device { #define ARM_SMMU_MAX_VMIDS (1 << 16) unsigned int vmid_bits; - DECLARE_BITMAP(vmid_map, ARM_SMMU_MAX_VMIDS); + struct ida vmid_map; unsigned int ssid_bits; unsigned int sid_bits; -- GitLab From 0a8c264d51ad3196a3239e731be51d2cc98f9337 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 5 Jul 2023 21:04:11 +0800 Subject: [PATCH 0637/3445] iommu/arm-smmu: Clean up resource handling during Qualcomm context probe Convert to use devm_platform_ioremap_resource() and fix return value when platform_get_irq fails. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230705130416.46710-1-frank.li@vivo.com Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu/qcom_iommu.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c index a503ed758ec30..abf798104830e 100644 --- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c +++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c @@ -633,7 +633,6 @@ static int qcom_iommu_ctx_probe(struct platform_device *pdev) struct qcom_iommu_ctx *ctx; struct device *dev = &pdev->dev; struct qcom_iommu_dev *qcom_iommu = dev_get_drvdata(dev->parent); - struct resource *res; int ret, irq; ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); @@ -643,14 +642,13 @@ static int qcom_iommu_ctx_probe(struct platform_device *pdev) ctx->dev = dev; platform_set_drvdata(pdev, ctx); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ctx->base = devm_ioremap_resource(dev, res); + ctx->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ctx->base)) return PTR_ERR(ctx->base); irq = platform_get_irq(pdev, 0); if (irq < 0) - return -ENODEV; + return irq; /* clear IRQs before registering fault handler, just in case the * boot-loader left us a surprise: -- GitLab From f1de55ff7c704b48389987f6c71ca31dc8cffe8d Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 29 Jul 2023 16:29:45 -0300 Subject: [PATCH 0638/3445] dmaengine: ipu: Remove the driver The i.MX3 IPU driver does not support devicetree and i.MX has been converted to a DT-only platform since kernel 5.10. As there is no user for this driver anymore, just remove it. Signed-off-by: Fabio Estevam Reviewed-by: Arnd Bergmann Link: https://lore.kernel.org/r/20230729192945.1217206-1-festevam@gmail.com Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 19 - drivers/dma/Makefile | 1 - drivers/dma/ipu/Makefile | 2 - drivers/dma/ipu/ipu_idmac.c | 1801 ---------------------------------- drivers/dma/ipu/ipu_intern.h | 173 ---- drivers/dma/ipu/ipu_irq.c | 367 ------- 6 files changed, 2363 deletions(-) delete mode 100644 drivers/dma/ipu/Makefile delete mode 100644 drivers/dma/ipu/ipu_idmac.c delete mode 100644 drivers/dma/ipu/ipu_intern.h delete mode 100644 drivers/dma/ipu/ipu_irq.c diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 0f9832f0ef586..1d485fce91c84 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -472,25 +472,6 @@ config MXS_DMA Support the MXS DMA engine. This engine including APBH-DMA and APBX-DMA is integrated into some Freescale chips. -config MX3_IPU - bool "MX3x Image Processing Unit support" - depends on ARCH_MXC - select DMA_ENGINE - default y - help - If you plan to use the Image Processing unit in the i.MX3x, say - Y here. If unsure, select Y. - -config MX3_IPU_IRQS - int "Number of dynamically mapped interrupts for IPU" - depends on MX3_IPU - range 2 137 - default 4 - help - Out of 137 interrupt sources on i.MX31 IPU only very few are used. - To avoid bloating the irq_desc[] array we allocate a sufficient - number of IRQ slots and map them dynamically to specific sources. - config NBPFAXI_DMA tristate "Renesas Type-AXI NBPF DMA support" select DMA_ENGINE diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index a4fd1ce295102..07cdfd27d09c6 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -55,7 +55,6 @@ obj-$(CONFIG_MPC512X_DMA) += mpc512x_dma.o obj-$(CONFIG_MV_XOR) += mv_xor.o obj-$(CONFIG_MV_XOR_V2) += mv_xor_v2.o obj-$(CONFIG_MXS_DMA) += mxs-dma.o -obj-$(CONFIG_MX3_IPU) += ipu/ obj-$(CONFIG_NBPFAXI_DMA) += nbpfaxi.o obj-$(CONFIG_OWL_DMA) += owl-dma.o obj-$(CONFIG_PCH_DMA) += pch_dma.o diff --git a/drivers/dma/ipu/Makefile b/drivers/dma/ipu/Makefile deleted file mode 100644 index c79ff116daf61..0000000000000 --- a/drivers/dma/ipu/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-y += ipu_irq.o ipu_idmac.o diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c deleted file mode 100644 index d799b99c18bda..0000000000000 --- a/drivers/dma/ipu/ipu_idmac.c +++ /dev/null @@ -1,1801 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2008 - * Guennadi Liakhovetski, DENX Software Engineering, - * - * Copyright (C) 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../dmaengine.h" -#include "ipu_intern.h" - -#define FS_VF_IN_VALID 0x00000002 -#define FS_ENC_IN_VALID 0x00000001 - -static int ipu_disable_channel(struct idmac *idmac, struct idmac_channel *ichan, - bool wait_for_stop); - -/* - * There can be only one, we could allocate it dynamically, but then we'd have - * to add an extra parameter to some functions, and use something as ugly as - * struct ipu *ipu = to_ipu(to_idmac(ichan->dma_chan.device)); - * in the ISR - */ -static struct ipu ipu_data; - -#define to_ipu(id) container_of(id, struct ipu, idmac) - -static u32 __idmac_read_icreg(struct ipu *ipu, unsigned long reg) -{ - return __raw_readl(ipu->reg_ic + reg); -} - -#define idmac_read_icreg(ipu, reg) __idmac_read_icreg(ipu, reg - IC_CONF) - -static void __idmac_write_icreg(struct ipu *ipu, u32 value, unsigned long reg) -{ - __raw_writel(value, ipu->reg_ic + reg); -} - -#define idmac_write_icreg(ipu, v, reg) __idmac_write_icreg(ipu, v, reg - IC_CONF) - -static u32 idmac_read_ipureg(struct ipu *ipu, unsigned long reg) -{ - return __raw_readl(ipu->reg_ipu + reg); -} - -static void idmac_write_ipureg(struct ipu *ipu, u32 value, unsigned long reg) -{ - __raw_writel(value, ipu->reg_ipu + reg); -} - -/***************************************************************************** - * IPU / IC common functions - */ -static void dump_idmac_reg(struct ipu *ipu) -{ - dev_dbg(ipu->dev, "IDMAC_CONF 0x%x, IC_CONF 0x%x, IDMAC_CHA_EN 0x%x, " - "IDMAC_CHA_PRI 0x%x, IDMAC_CHA_BUSY 0x%x\n", - idmac_read_icreg(ipu, IDMAC_CONF), - idmac_read_icreg(ipu, IC_CONF), - idmac_read_icreg(ipu, IDMAC_CHA_EN), - idmac_read_icreg(ipu, IDMAC_CHA_PRI), - idmac_read_icreg(ipu, IDMAC_CHA_BUSY)); - dev_dbg(ipu->dev, "BUF0_RDY 0x%x, BUF1_RDY 0x%x, CUR_BUF 0x%x, " - "DB_MODE 0x%x, TASKS_STAT 0x%x\n", - idmac_read_ipureg(ipu, IPU_CHA_BUF0_RDY), - idmac_read_ipureg(ipu, IPU_CHA_BUF1_RDY), - idmac_read_ipureg(ipu, IPU_CHA_CUR_BUF), - idmac_read_ipureg(ipu, IPU_CHA_DB_MODE_SEL), - idmac_read_ipureg(ipu, IPU_TASKS_STAT)); -} - -static uint32_t bytes_per_pixel(enum pixel_fmt fmt) -{ - switch (fmt) { - case IPU_PIX_FMT_GENERIC: /* generic data */ - case IPU_PIX_FMT_RGB332: - case IPU_PIX_FMT_YUV420P: - case IPU_PIX_FMT_YUV422P: - default: - return 1; - case IPU_PIX_FMT_RGB565: - case IPU_PIX_FMT_YUYV: - case IPU_PIX_FMT_UYVY: - return 2; - case IPU_PIX_FMT_BGR24: - case IPU_PIX_FMT_RGB24: - return 3; - case IPU_PIX_FMT_GENERIC_32: /* generic data */ - case IPU_PIX_FMT_BGR32: - case IPU_PIX_FMT_RGB32: - case IPU_PIX_FMT_ABGR32: - return 4; - } -} - -/* Enable direct write to memory by the Camera Sensor Interface */ -static void ipu_ic_enable_task(struct ipu *ipu, enum ipu_channel channel) -{ - uint32_t ic_conf, mask; - - switch (channel) { - case IDMAC_IC_0: - mask = IC_CONF_PRPENC_EN; - break; - case IDMAC_IC_7: - mask = IC_CONF_RWS_EN | IC_CONF_PRPENC_EN; - break; - default: - return; - } - ic_conf = idmac_read_icreg(ipu, IC_CONF) | mask; - idmac_write_icreg(ipu, ic_conf, IC_CONF); -} - -/* Called under spin_lock_irqsave(&ipu_data.lock) */ -static void ipu_ic_disable_task(struct ipu *ipu, enum ipu_channel channel) -{ - uint32_t ic_conf, mask; - - switch (channel) { - case IDMAC_IC_0: - mask = IC_CONF_PRPENC_EN; - break; - case IDMAC_IC_7: - mask = IC_CONF_RWS_EN | IC_CONF_PRPENC_EN; - break; - default: - return; - } - ic_conf = idmac_read_icreg(ipu, IC_CONF) & ~mask; - idmac_write_icreg(ipu, ic_conf, IC_CONF); -} - -static uint32_t ipu_channel_status(struct ipu *ipu, enum ipu_channel channel) -{ - uint32_t stat = TASK_STAT_IDLE; - uint32_t task_stat_reg = idmac_read_ipureg(ipu, IPU_TASKS_STAT); - - switch (channel) { - case IDMAC_IC_7: - stat = (task_stat_reg & TSTAT_CSI2MEM_MASK) >> - TSTAT_CSI2MEM_OFFSET; - break; - case IDMAC_IC_0: - case IDMAC_SDC_0: - case IDMAC_SDC_1: - default: - break; - } - return stat; -} - -struct chan_param_mem_planar { - /* Word 0 */ - u32 xv:10; - u32 yv:10; - u32 xb:12; - - u32 yb:12; - u32 res1:2; - u32 nsb:1; - u32 lnpb:6; - u32 ubo_l:11; - - u32 ubo_h:15; - u32 vbo_l:17; - - u32 vbo_h:9; - u32 res2:3; - u32 fw:12; - u32 fh_l:8; - - u32 fh_h:4; - u32 res3:28; - - /* Word 1 */ - u32 eba0; - - u32 eba1; - - u32 bpp:3; - u32 sl:14; - u32 pfs:3; - u32 bam:3; - u32 res4:2; - u32 npb:6; - u32 res5:1; - - u32 sat:2; - u32 res6:30; -} __attribute__ ((packed)); - -struct chan_param_mem_interleaved { - /* Word 0 */ - u32 xv:10; - u32 yv:10; - u32 xb:12; - - u32 yb:12; - u32 sce:1; - u32 res1:1; - u32 nsb:1; - u32 lnpb:6; - u32 sx:10; - u32 sy_l:1; - - u32 sy_h:9; - u32 ns:10; - u32 sm:10; - u32 sdx_l:3; - - u32 sdx_h:2; - u32 sdy:5; - u32 sdrx:1; - u32 sdry:1; - u32 sdr1:1; - u32 res2:2; - u32 fw:12; - u32 fh_l:8; - - u32 fh_h:4; - u32 res3:28; - - /* Word 1 */ - u32 eba0; - - u32 eba1; - - u32 bpp:3; - u32 sl:14; - u32 pfs:3; - u32 bam:3; - u32 res4:2; - u32 npb:6; - u32 res5:1; - - u32 sat:2; - u32 scc:1; - u32 ofs0:5; - u32 ofs1:5; - u32 ofs2:5; - u32 ofs3:5; - u32 wid0:3; - u32 wid1:3; - u32 wid2:3; - - u32 wid3:3; - u32 dec_sel:1; - u32 res6:28; -} __attribute__ ((packed)); - -union chan_param_mem { - struct chan_param_mem_planar pp; - struct chan_param_mem_interleaved ip; -}; - -static void ipu_ch_param_set_plane_offset(union chan_param_mem *params, - u32 u_offset, u32 v_offset) -{ - params->pp.ubo_l = u_offset & 0x7ff; - params->pp.ubo_h = u_offset >> 11; - params->pp.vbo_l = v_offset & 0x1ffff; - params->pp.vbo_h = v_offset >> 17; -} - -static void ipu_ch_param_set_size(union chan_param_mem *params, - uint32_t pixel_fmt, uint16_t width, - uint16_t height, uint16_t stride) -{ - u32 u_offset; - u32 v_offset; - - params->pp.fw = width - 1; - params->pp.fh_l = height - 1; - params->pp.fh_h = (height - 1) >> 8; - params->pp.sl = stride - 1; - - switch (pixel_fmt) { - case IPU_PIX_FMT_GENERIC: - /*Represents 8-bit Generic data */ - params->pp.bpp = 3; - params->pp.pfs = 7; - params->pp.npb = 31; - params->pp.sat = 2; /* SAT = use 32-bit access */ - break; - case IPU_PIX_FMT_GENERIC_32: - /*Represents 32-bit Generic data */ - params->pp.bpp = 0; - params->pp.pfs = 7; - params->pp.npb = 7; - params->pp.sat = 2; /* SAT = use 32-bit access */ - break; - case IPU_PIX_FMT_RGB565: - params->ip.bpp = 2; - params->ip.pfs = 4; - params->ip.npb = 15; - params->ip.sat = 2; /* SAT = 32-bit access */ - params->ip.ofs0 = 0; /* Red bit offset */ - params->ip.ofs1 = 5; /* Green bit offset */ - params->ip.ofs2 = 11; /* Blue bit offset */ - params->ip.ofs3 = 16; /* Alpha bit offset */ - params->ip.wid0 = 4; /* Red bit width - 1 */ - params->ip.wid1 = 5; /* Green bit width - 1 */ - params->ip.wid2 = 4; /* Blue bit width - 1 */ - break; - case IPU_PIX_FMT_BGR24: - params->ip.bpp = 1; /* 24 BPP & RGB PFS */ - params->ip.pfs = 4; - params->ip.npb = 7; - params->ip.sat = 2; /* SAT = 32-bit access */ - params->ip.ofs0 = 0; /* Red bit offset */ - params->ip.ofs1 = 8; /* Green bit offset */ - params->ip.ofs2 = 16; /* Blue bit offset */ - params->ip.ofs3 = 24; /* Alpha bit offset */ - params->ip.wid0 = 7; /* Red bit width - 1 */ - params->ip.wid1 = 7; /* Green bit width - 1 */ - params->ip.wid2 = 7; /* Blue bit width - 1 */ - break; - case IPU_PIX_FMT_RGB24: - params->ip.bpp = 1; /* 24 BPP & RGB PFS */ - params->ip.pfs = 4; - params->ip.npb = 7; - params->ip.sat = 2; /* SAT = 32-bit access */ - params->ip.ofs0 = 16; /* Red bit offset */ - params->ip.ofs1 = 8; /* Green bit offset */ - params->ip.ofs2 = 0; /* Blue bit offset */ - params->ip.ofs3 = 24; /* Alpha bit offset */ - params->ip.wid0 = 7; /* Red bit width - 1 */ - params->ip.wid1 = 7; /* Green bit width - 1 */ - params->ip.wid2 = 7; /* Blue bit width - 1 */ - break; - case IPU_PIX_FMT_BGRA32: - case IPU_PIX_FMT_BGR32: - case IPU_PIX_FMT_ABGR32: - params->ip.bpp = 0; - params->ip.pfs = 4; - params->ip.npb = 7; - params->ip.sat = 2; /* SAT = 32-bit access */ - params->ip.ofs0 = 8; /* Red bit offset */ - params->ip.ofs1 = 16; /* Green bit offset */ - params->ip.ofs2 = 24; /* Blue bit offset */ - params->ip.ofs3 = 0; /* Alpha bit offset */ - params->ip.wid0 = 7; /* Red bit width - 1 */ - params->ip.wid1 = 7; /* Green bit width - 1 */ - params->ip.wid2 = 7; /* Blue bit width - 1 */ - params->ip.wid3 = 7; /* Alpha bit width - 1 */ - break; - case IPU_PIX_FMT_RGBA32: - case IPU_PIX_FMT_RGB32: - params->ip.bpp = 0; - params->ip.pfs = 4; - params->ip.npb = 7; - params->ip.sat = 2; /* SAT = 32-bit access */ - params->ip.ofs0 = 24; /* Red bit offset */ - params->ip.ofs1 = 16; /* Green bit offset */ - params->ip.ofs2 = 8; /* Blue bit offset */ - params->ip.ofs3 = 0; /* Alpha bit offset */ - params->ip.wid0 = 7; /* Red bit width - 1 */ - params->ip.wid1 = 7; /* Green bit width - 1 */ - params->ip.wid2 = 7; /* Blue bit width - 1 */ - params->ip.wid3 = 7; /* Alpha bit width - 1 */ - break; - case IPU_PIX_FMT_UYVY: - params->ip.bpp = 2; - params->ip.pfs = 6; - params->ip.npb = 7; - params->ip.sat = 2; /* SAT = 32-bit access */ - break; - case IPU_PIX_FMT_YUV420P2: - case IPU_PIX_FMT_YUV420P: - params->ip.bpp = 3; - params->ip.pfs = 3; - params->ip.npb = 7; - params->ip.sat = 2; /* SAT = 32-bit access */ - u_offset = stride * height; - v_offset = u_offset + u_offset / 4; - ipu_ch_param_set_plane_offset(params, u_offset, v_offset); - break; - case IPU_PIX_FMT_YVU422P: - params->ip.bpp = 3; - params->ip.pfs = 2; - params->ip.npb = 7; - params->ip.sat = 2; /* SAT = 32-bit access */ - v_offset = stride * height; - u_offset = v_offset + v_offset / 2; - ipu_ch_param_set_plane_offset(params, u_offset, v_offset); - break; - case IPU_PIX_FMT_YUV422P: - params->ip.bpp = 3; - params->ip.pfs = 2; - params->ip.npb = 7; - params->ip.sat = 2; /* SAT = 32-bit access */ - u_offset = stride * height; - v_offset = u_offset + u_offset / 2; - ipu_ch_param_set_plane_offset(params, u_offset, v_offset); - break; - default: - dev_err(ipu_data.dev, - "mx3 ipu: unimplemented pixel format %d\n", pixel_fmt); - break; - } - - params->pp.nsb = 1; -} - -static void ipu_ch_param_set_buffer(union chan_param_mem *params, - dma_addr_t buf0, dma_addr_t buf1) -{ - params->pp.eba0 = buf0; - params->pp.eba1 = buf1; -} - -static void ipu_ch_param_set_rotation(union chan_param_mem *params, - enum ipu_rotate_mode rotate) -{ - params->pp.bam = rotate; -} - -static void ipu_write_param_mem(uint32_t addr, uint32_t *data, - uint32_t num_words) -{ - for (; num_words > 0; num_words--) { - dev_dbg(ipu_data.dev, - "write param mem - addr = 0x%08X, data = 0x%08X\n", - addr, *data); - idmac_write_ipureg(&ipu_data, addr, IPU_IMA_ADDR); - idmac_write_ipureg(&ipu_data, *data++, IPU_IMA_DATA); - addr++; - if ((addr & 0x7) == 5) { - addr &= ~0x7; /* set to word 0 */ - addr += 8; /* increment to next row */ - } - } -} - -static int calc_resize_coeffs(uint32_t in_size, uint32_t out_size, - uint32_t *resize_coeff, - uint32_t *downsize_coeff) -{ - uint32_t temp_size; - uint32_t temp_downsize; - - *resize_coeff = 1 << 13; - *downsize_coeff = 1 << 13; - - /* Cannot downsize more than 8:1 */ - if (out_size << 3 < in_size) - return -EINVAL; - - /* compute downsizing coefficient */ - temp_downsize = 0; - temp_size = in_size; - while (temp_size >= out_size * 2 && temp_downsize < 2) { - temp_size >>= 1; - temp_downsize++; - } - *downsize_coeff = temp_downsize; - - /* - * compute resizing coefficient using the following formula: - * resize_coeff = M*(SI -1)/(SO - 1) - * where M = 2^13, SI - input size, SO - output size - */ - *resize_coeff = (8192L * (temp_size - 1)) / (out_size - 1); - if (*resize_coeff >= 16384L) { - dev_err(ipu_data.dev, "Warning! Overflow on resize coeff.\n"); - *resize_coeff = 0x3FFF; - } - - dev_dbg(ipu_data.dev, "resizing from %u -> %u pixels, " - "downsize=%u, resize=%u.%lu (reg=%u)\n", in_size, out_size, - *downsize_coeff, *resize_coeff >= 8192L ? 1 : 0, - ((*resize_coeff & 0x1FFF) * 10000L) / 8192L, *resize_coeff); - - return 0; -} - -static enum ipu_color_space format_to_colorspace(enum pixel_fmt fmt) -{ - switch (fmt) { - case IPU_PIX_FMT_RGB565: - case IPU_PIX_FMT_BGR24: - case IPU_PIX_FMT_RGB24: - case IPU_PIX_FMT_BGR32: - case IPU_PIX_FMT_RGB32: - return IPU_COLORSPACE_RGB; - default: - return IPU_COLORSPACE_YCBCR; - } -} - -static int ipu_ic_init_prpenc(struct ipu *ipu, - union ipu_channel_param *params, bool src_is_csi) -{ - uint32_t reg, ic_conf; - uint32_t downsize_coeff, resize_coeff; - enum ipu_color_space in_fmt, out_fmt; - - /* Setup vertical resizing */ - calc_resize_coeffs(params->video.in_height, - params->video.out_height, - &resize_coeff, &downsize_coeff); - reg = (downsize_coeff << 30) | (resize_coeff << 16); - - /* Setup horizontal resizing */ - calc_resize_coeffs(params->video.in_width, - params->video.out_width, - &resize_coeff, &downsize_coeff); - reg |= (downsize_coeff << 14) | resize_coeff; - - /* Setup color space conversion */ - in_fmt = format_to_colorspace(params->video.in_pixel_fmt); - out_fmt = format_to_colorspace(params->video.out_pixel_fmt); - - /* - * Colourspace conversion unsupported yet - see _init_csc() in - * Freescale sources - */ - if (in_fmt != out_fmt) { - dev_err(ipu->dev, "Colourspace conversion unsupported!\n"); - return -EOPNOTSUPP; - } - - idmac_write_icreg(ipu, reg, IC_PRP_ENC_RSC); - - ic_conf = idmac_read_icreg(ipu, IC_CONF); - - if (src_is_csi) - ic_conf &= ~IC_CONF_RWS_EN; - else - ic_conf |= IC_CONF_RWS_EN; - - idmac_write_icreg(ipu, ic_conf, IC_CONF); - - return 0; -} - -static uint32_t dma_param_addr(uint32_t dma_ch) -{ - /* Channel Parameter Memory */ - return 0x10000 | (dma_ch << 4); -} - -static void ipu_channel_set_priority(struct ipu *ipu, enum ipu_channel channel, - bool prio) -{ - u32 reg = idmac_read_icreg(ipu, IDMAC_CHA_PRI); - - if (prio) - reg |= 1UL << channel; - else - reg &= ~(1UL << channel); - - idmac_write_icreg(ipu, reg, IDMAC_CHA_PRI); - - dump_idmac_reg(ipu); -} - -static uint32_t ipu_channel_conf_mask(enum ipu_channel channel) -{ - uint32_t mask; - - switch (channel) { - case IDMAC_IC_0: - case IDMAC_IC_7: - mask = IPU_CONF_CSI_EN | IPU_CONF_IC_EN; - break; - case IDMAC_SDC_0: - case IDMAC_SDC_1: - mask = IPU_CONF_SDC_EN | IPU_CONF_DI_EN; - break; - default: - mask = 0; - break; - } - - return mask; -} - -/** - * ipu_enable_channel() - enable an IPU channel. - * @idmac: IPU DMAC context. - * @ichan: IDMAC channel. - * @return: 0 on success or negative error code on failure. - */ -static int ipu_enable_channel(struct idmac *idmac, struct idmac_channel *ichan) -{ - struct ipu *ipu = to_ipu(idmac); - enum ipu_channel channel = ichan->dma_chan.chan_id; - uint32_t reg; - unsigned long flags; - - spin_lock_irqsave(&ipu->lock, flags); - - /* Reset to buffer 0 */ - idmac_write_ipureg(ipu, 1UL << channel, IPU_CHA_CUR_BUF); - ichan->active_buffer = 0; - ichan->status = IPU_CHANNEL_ENABLED; - - switch (channel) { - case IDMAC_SDC_0: - case IDMAC_SDC_1: - case IDMAC_IC_7: - ipu_channel_set_priority(ipu, channel, true); - break; - default: - break; - } - - reg = idmac_read_icreg(ipu, IDMAC_CHA_EN); - - idmac_write_icreg(ipu, reg | (1UL << channel), IDMAC_CHA_EN); - - ipu_ic_enable_task(ipu, channel); - - spin_unlock_irqrestore(&ipu->lock, flags); - return 0; -} - -/** - * ipu_init_channel_buffer() - initialize a buffer for logical IPU channel. - * @ichan: IDMAC channel. - * @pixel_fmt: pixel format of buffer. Pixel format is a FOURCC ASCII code. - * @width: width of buffer in pixels. - * @height: height of buffer in pixels. - * @stride: stride length of buffer in pixels. - * @rot_mode: rotation mode of buffer. A rotation setting other than - * IPU_ROTATE_VERT_FLIP should only be used for input buffers of - * rotation channels. - * @phyaddr_0: buffer 0 physical address. - * @phyaddr_1: buffer 1 physical address. Setting this to a value other than - * NULL enables double buffering mode. - * @return: 0 on success or negative error code on failure. - */ -static int ipu_init_channel_buffer(struct idmac_channel *ichan, - enum pixel_fmt pixel_fmt, - uint16_t width, uint16_t height, - uint32_t stride, - enum ipu_rotate_mode rot_mode, - dma_addr_t phyaddr_0, dma_addr_t phyaddr_1) -{ - enum ipu_channel channel = ichan->dma_chan.chan_id; - struct idmac *idmac = to_idmac(ichan->dma_chan.device); - struct ipu *ipu = to_ipu(idmac); - union chan_param_mem params = {}; - unsigned long flags; - uint32_t reg; - uint32_t stride_bytes; - - stride_bytes = stride * bytes_per_pixel(pixel_fmt); - - if (stride_bytes % 4) { - dev_err(ipu->dev, - "Stride length must be 32-bit aligned, stride = %d, bytes = %d\n", - stride, stride_bytes); - return -EINVAL; - } - - /* IC channel's stride must be a multiple of 8 pixels */ - if ((channel <= IDMAC_IC_13) && (stride % 8)) { - dev_err(ipu->dev, "Stride must be 8 pixel multiple\n"); - return -EINVAL; - } - - /* Build parameter memory data for DMA channel */ - ipu_ch_param_set_size(¶ms, pixel_fmt, width, height, stride_bytes); - ipu_ch_param_set_buffer(¶ms, phyaddr_0, phyaddr_1); - ipu_ch_param_set_rotation(¶ms, rot_mode); - - spin_lock_irqsave(&ipu->lock, flags); - - ipu_write_param_mem(dma_param_addr(channel), (uint32_t *)¶ms, 10); - - reg = idmac_read_ipureg(ipu, IPU_CHA_DB_MODE_SEL); - - if (phyaddr_1) - reg |= 1UL << channel; - else - reg &= ~(1UL << channel); - - idmac_write_ipureg(ipu, reg, IPU_CHA_DB_MODE_SEL); - - ichan->status = IPU_CHANNEL_READY; - - spin_unlock_irqrestore(&ipu->lock, flags); - - return 0; -} - -/** - * ipu_select_buffer() - mark a channel's buffer as ready. - * @channel: channel ID. - * @buffer_n: buffer number to mark ready. - */ -static void ipu_select_buffer(enum ipu_channel channel, int buffer_n) -{ - /* No locking - this is a write-one-to-set register, cleared by IPU */ - if (buffer_n == 0) - /* Mark buffer 0 as ready. */ - idmac_write_ipureg(&ipu_data, 1UL << channel, IPU_CHA_BUF0_RDY); - else - /* Mark buffer 1 as ready. */ - idmac_write_ipureg(&ipu_data, 1UL << channel, IPU_CHA_BUF1_RDY); -} - -/** - * ipu_update_channel_buffer() - update physical address of a channel buffer. - * @ichan: IDMAC channel. - * @buffer_n: buffer number to update. - * 0 or 1 are the only valid values. - * @phyaddr: buffer physical address. - */ -/* Called under spin_lock(_irqsave)(&ichan->lock) */ -static void ipu_update_channel_buffer(struct idmac_channel *ichan, - int buffer_n, dma_addr_t phyaddr) -{ - enum ipu_channel channel = ichan->dma_chan.chan_id; - uint32_t reg; - unsigned long flags; - - spin_lock_irqsave(&ipu_data.lock, flags); - - if (buffer_n == 0) { - reg = idmac_read_ipureg(&ipu_data, IPU_CHA_BUF0_RDY); - if (reg & (1UL << channel)) { - ipu_ic_disable_task(&ipu_data, channel); - ichan->status = IPU_CHANNEL_READY; - } - - /* 44.3.3.1.9 - Row Number 1 (WORD1, offset 0) */ - idmac_write_ipureg(&ipu_data, dma_param_addr(channel) + - 0x0008UL, IPU_IMA_ADDR); - idmac_write_ipureg(&ipu_data, phyaddr, IPU_IMA_DATA); - } else { - reg = idmac_read_ipureg(&ipu_data, IPU_CHA_BUF1_RDY); - if (reg & (1UL << channel)) { - ipu_ic_disable_task(&ipu_data, channel); - ichan->status = IPU_CHANNEL_READY; - } - - /* Check if double-buffering is already enabled */ - reg = idmac_read_ipureg(&ipu_data, IPU_CHA_DB_MODE_SEL); - - if (!(reg & (1UL << channel))) - idmac_write_ipureg(&ipu_data, reg | (1UL << channel), - IPU_CHA_DB_MODE_SEL); - - /* 44.3.3.1.9 - Row Number 1 (WORD1, offset 1) */ - idmac_write_ipureg(&ipu_data, dma_param_addr(channel) + - 0x0009UL, IPU_IMA_ADDR); - idmac_write_ipureg(&ipu_data, phyaddr, IPU_IMA_DATA); - } - - spin_unlock_irqrestore(&ipu_data.lock, flags); -} - -/* Called under spin_lock_irqsave(&ichan->lock) */ -static int ipu_submit_buffer(struct idmac_channel *ichan, - struct idmac_tx_desc *desc, struct scatterlist *sg, int buf_idx) -{ - unsigned int chan_id = ichan->dma_chan.chan_id; - struct device *dev = &ichan->dma_chan.dev->device; - - if (async_tx_test_ack(&desc->txd)) - return -EINTR; - - /* - * On first invocation this shouldn't be necessary, the call to - * ipu_init_channel_buffer() above will set addresses for us, so we - * could make it conditional on status >= IPU_CHANNEL_ENABLED, but - * doing it again shouldn't hurt either. - */ - ipu_update_channel_buffer(ichan, buf_idx, sg_dma_address(sg)); - - ipu_select_buffer(chan_id, buf_idx); - dev_dbg(dev, "Updated sg %p on channel 0x%x buffer %d\n", - sg, chan_id, buf_idx); - - return 0; -} - -/* Called under spin_lock_irqsave(&ichan->lock) */ -static int ipu_submit_channel_buffers(struct idmac_channel *ichan, - struct idmac_tx_desc *desc) -{ - struct scatterlist *sg; - int i, ret = 0; - - for (i = 0, sg = desc->sg; i < 2 && sg; i++) { - if (!ichan->sg[i]) { - ichan->sg[i] = sg; - - ret = ipu_submit_buffer(ichan, desc, sg, i); - if (ret < 0) - return ret; - - sg = sg_next(sg); - } - } - - return ret; -} - -static dma_cookie_t idmac_tx_submit(struct dma_async_tx_descriptor *tx) -{ - struct idmac_tx_desc *desc = to_tx_desc(tx); - struct idmac_channel *ichan = to_idmac_chan(tx->chan); - struct idmac *idmac = to_idmac(tx->chan->device); - struct ipu *ipu = to_ipu(idmac); - struct device *dev = &ichan->dma_chan.dev->device; - dma_cookie_t cookie; - unsigned long flags; - int ret; - - /* Sanity check */ - if (!list_empty(&desc->list)) { - /* The descriptor doesn't belong to client */ - dev_err(dev, "Descriptor %p not prepared!\n", tx); - return -EBUSY; - } - - mutex_lock(&ichan->chan_mutex); - - async_tx_clear_ack(tx); - - if (ichan->status < IPU_CHANNEL_READY) { - struct idmac_video_param *video = &ichan->params.video; - /* - * Initial buffer assignment - the first two sg-entries from - * the descriptor will end up in the IDMAC buffers - */ - dma_addr_t dma_1 = sg_is_last(desc->sg) ? 0 : - sg_dma_address(&desc->sg[1]); - - WARN_ON(ichan->sg[0] || ichan->sg[1]); - - cookie = ipu_init_channel_buffer(ichan, - video->out_pixel_fmt, - video->out_width, - video->out_height, - video->out_stride, - IPU_ROTATE_NONE, - sg_dma_address(&desc->sg[0]), - dma_1); - if (cookie < 0) - goto out; - } - - dev_dbg(dev, "Submitting sg %p\n", &desc->sg[0]); - - cookie = dma_cookie_assign(tx); - - /* ipu->lock can be taken under ichan->lock, but not v.v. */ - spin_lock_irqsave(&ichan->lock, flags); - - list_add_tail(&desc->list, &ichan->queue); - /* submit_buffers() atomically verifies and fills empty sg slots */ - ret = ipu_submit_channel_buffers(ichan, desc); - - spin_unlock_irqrestore(&ichan->lock, flags); - - if (ret < 0) { - cookie = ret; - goto dequeue; - } - - if (ichan->status < IPU_CHANNEL_ENABLED) { - ret = ipu_enable_channel(idmac, ichan); - if (ret < 0) { - cookie = ret; - goto dequeue; - } - } - - dump_idmac_reg(ipu); - -dequeue: - if (cookie < 0) { - spin_lock_irqsave(&ichan->lock, flags); - list_del_init(&desc->list); - spin_unlock_irqrestore(&ichan->lock, flags); - tx->cookie = cookie; - ichan->dma_chan.cookie = cookie; - } - -out: - mutex_unlock(&ichan->chan_mutex); - - return cookie; -} - -/* Called with ichan->chan_mutex held */ -static int idmac_desc_alloc(struct idmac_channel *ichan, int n) -{ - struct idmac_tx_desc *desc = - vmalloc(array_size(n, sizeof(struct idmac_tx_desc))); - struct idmac *idmac = to_idmac(ichan->dma_chan.device); - - if (!desc) - return -ENOMEM; - - /* No interrupts, just disable the tasklet for a moment */ - tasklet_disable(&to_ipu(idmac)->tasklet); - - ichan->n_tx_desc = n; - ichan->desc = desc; - INIT_LIST_HEAD(&ichan->queue); - INIT_LIST_HEAD(&ichan->free_list); - - while (n--) { - struct dma_async_tx_descriptor *txd = &desc->txd; - - memset(txd, 0, sizeof(*txd)); - dma_async_tx_descriptor_init(txd, &ichan->dma_chan); - txd->tx_submit = idmac_tx_submit; - - list_add(&desc->list, &ichan->free_list); - - desc++; - } - - tasklet_enable(&to_ipu(idmac)->tasklet); - - return 0; -} - -/** - * ipu_init_channel() - initialize an IPU channel. - * @idmac: IPU DMAC context. - * @ichan: pointer to the channel object. - * @return 0 on success or negative error code on failure. - */ -static int ipu_init_channel(struct idmac *idmac, struct idmac_channel *ichan) -{ - union ipu_channel_param *params = &ichan->params; - uint32_t ipu_conf; - enum ipu_channel channel = ichan->dma_chan.chan_id; - unsigned long flags; - uint32_t reg; - struct ipu *ipu = to_ipu(idmac); - int ret = 0, n_desc = 0; - - dev_dbg(ipu->dev, "init channel = %d\n", channel); - - if (channel != IDMAC_SDC_0 && channel != IDMAC_SDC_1 && - channel != IDMAC_IC_7) - return -EINVAL; - - spin_lock_irqsave(&ipu->lock, flags); - - switch (channel) { - case IDMAC_IC_7: - n_desc = 16; - reg = idmac_read_icreg(ipu, IC_CONF); - idmac_write_icreg(ipu, reg & ~IC_CONF_CSI_MEM_WR_EN, IC_CONF); - break; - case IDMAC_IC_0: - n_desc = 16; - reg = idmac_read_ipureg(ipu, IPU_FS_PROC_FLOW); - idmac_write_ipureg(ipu, reg & ~FS_ENC_IN_VALID, IPU_FS_PROC_FLOW); - ret = ipu_ic_init_prpenc(ipu, params, true); - break; - case IDMAC_SDC_0: - case IDMAC_SDC_1: - n_desc = 4; - break; - default: - break; - } - - ipu->channel_init_mask |= 1L << channel; - - /* Enable IPU sub module */ - ipu_conf = idmac_read_ipureg(ipu, IPU_CONF) | - ipu_channel_conf_mask(channel); - idmac_write_ipureg(ipu, ipu_conf, IPU_CONF); - - spin_unlock_irqrestore(&ipu->lock, flags); - - if (n_desc && !ichan->desc) - ret = idmac_desc_alloc(ichan, n_desc); - - dump_idmac_reg(ipu); - - return ret; -} - -/** - * ipu_uninit_channel() - uninitialize an IPU channel. - * @idmac: IPU DMAC context. - * @ichan: pointer to the channel object. - */ -static void ipu_uninit_channel(struct idmac *idmac, struct idmac_channel *ichan) -{ - enum ipu_channel channel = ichan->dma_chan.chan_id; - unsigned long flags; - uint32_t reg; - unsigned long chan_mask = 1UL << channel; - uint32_t ipu_conf; - struct ipu *ipu = to_ipu(idmac); - - spin_lock_irqsave(&ipu->lock, flags); - - if (!(ipu->channel_init_mask & chan_mask)) { - dev_err(ipu->dev, "Channel already uninitialized %d\n", - channel); - spin_unlock_irqrestore(&ipu->lock, flags); - return; - } - - /* Reset the double buffer */ - reg = idmac_read_ipureg(ipu, IPU_CHA_DB_MODE_SEL); - idmac_write_ipureg(ipu, reg & ~chan_mask, IPU_CHA_DB_MODE_SEL); - - ichan->sec_chan_en = false; - - switch (channel) { - case IDMAC_IC_7: - reg = idmac_read_icreg(ipu, IC_CONF); - idmac_write_icreg(ipu, reg & ~(IC_CONF_RWS_EN | IC_CONF_PRPENC_EN), - IC_CONF); - break; - case IDMAC_IC_0: - reg = idmac_read_icreg(ipu, IC_CONF); - idmac_write_icreg(ipu, reg & ~(IC_CONF_PRPENC_EN | IC_CONF_PRPENC_CSC1), - IC_CONF); - break; - case IDMAC_SDC_0: - case IDMAC_SDC_1: - default: - break; - } - - ipu->channel_init_mask &= ~(1L << channel); - - ipu_conf = idmac_read_ipureg(ipu, IPU_CONF) & - ~ipu_channel_conf_mask(channel); - idmac_write_ipureg(ipu, ipu_conf, IPU_CONF); - - spin_unlock_irqrestore(&ipu->lock, flags); - - ichan->n_tx_desc = 0; - vfree(ichan->desc); - ichan->desc = NULL; -} - -/** - * ipu_disable_channel() - disable an IPU channel. - * @idmac: IPU DMAC context. - * @ichan: channel object pointer. - * @wait_for_stop: flag to set whether to wait for channel end of frame or - * return immediately. - * @return: 0 on success or negative error code on failure. - */ -static int ipu_disable_channel(struct idmac *idmac, struct idmac_channel *ichan, - bool wait_for_stop) -{ - enum ipu_channel channel = ichan->dma_chan.chan_id; - struct ipu *ipu = to_ipu(idmac); - uint32_t reg; - unsigned long flags; - unsigned long chan_mask = 1UL << channel; - unsigned int timeout; - - if (wait_for_stop && channel != IDMAC_SDC_1 && channel != IDMAC_SDC_0) { - timeout = 40; - /* This waiting always fails. Related to spurious irq problem */ - while ((idmac_read_icreg(ipu, IDMAC_CHA_BUSY) & chan_mask) || - (ipu_channel_status(ipu, channel) == TASK_STAT_ACTIVE)) { - timeout--; - msleep(10); - - if (!timeout) { - dev_dbg(ipu->dev, - "Warning: timeout waiting for channel %u to " - "stop: buf0_rdy = 0x%08X, buf1_rdy = 0x%08X, " - "busy = 0x%08X, tstat = 0x%08X\n", channel, - idmac_read_ipureg(ipu, IPU_CHA_BUF0_RDY), - idmac_read_ipureg(ipu, IPU_CHA_BUF1_RDY), - idmac_read_icreg(ipu, IDMAC_CHA_BUSY), - idmac_read_ipureg(ipu, IPU_TASKS_STAT)); - break; - } - } - dev_dbg(ipu->dev, "timeout = %d * 10ms\n", 40 - timeout); - } - /* SDC BG and FG must be disabled before DMA is disabled */ - if (wait_for_stop && (channel == IDMAC_SDC_0 || - channel == IDMAC_SDC_1)) { - for (timeout = 5; - timeout && !ipu_irq_status(ichan->eof_irq); timeout--) - msleep(5); - } - - spin_lock_irqsave(&ipu->lock, flags); - - /* Disable IC task */ - ipu_ic_disable_task(ipu, channel); - - /* Disable DMA channel(s) */ - reg = idmac_read_icreg(ipu, IDMAC_CHA_EN); - idmac_write_icreg(ipu, reg & ~chan_mask, IDMAC_CHA_EN); - - spin_unlock_irqrestore(&ipu->lock, flags); - - return 0; -} - -static struct scatterlist *idmac_sg_next(struct idmac_channel *ichan, - struct idmac_tx_desc **desc, struct scatterlist *sg) -{ - struct scatterlist *sgnew = sg ? sg_next(sg) : NULL; - - if (sgnew) - /* next sg-element in this list */ - return sgnew; - - if ((*desc)->list.next == &ichan->queue) - /* No more descriptors on the queue */ - return NULL; - - /* Fetch next descriptor */ - *desc = list_entry((*desc)->list.next, struct idmac_tx_desc, list); - return (*desc)->sg; -} - -/* - * We have several possibilities here: - * current BUF next BUF - * - * not last sg next not last sg - * not last sg next last sg - * last sg first sg from next descriptor - * last sg NULL - * - * Besides, the descriptor queue might be empty or not. We process all these - * cases carefully. - */ -static irqreturn_t idmac_interrupt(int irq, void *dev_id) -{ - struct idmac_channel *ichan = dev_id; - struct device *dev = &ichan->dma_chan.dev->device; - unsigned int chan_id = ichan->dma_chan.chan_id; - struct scatterlist **sg, *sgnext, *sgnew = NULL; - /* Next transfer descriptor */ - struct idmac_tx_desc *desc, *descnew; - bool done = false; - u32 ready0, ready1, curbuf, err; - struct dmaengine_desc_callback cb; - - /* IDMAC has cleared the respective BUFx_RDY bit, we manage the buffer */ - - dev_dbg(dev, "IDMAC irq %d, buf %d\n", irq, ichan->active_buffer); - - spin_lock(&ipu_data.lock); - - ready0 = idmac_read_ipureg(&ipu_data, IPU_CHA_BUF0_RDY); - ready1 = idmac_read_ipureg(&ipu_data, IPU_CHA_BUF1_RDY); - curbuf = idmac_read_ipureg(&ipu_data, IPU_CHA_CUR_BUF); - err = idmac_read_ipureg(&ipu_data, IPU_INT_STAT_4); - - if (err & (1 << chan_id)) { - idmac_write_ipureg(&ipu_data, 1 << chan_id, IPU_INT_STAT_4); - spin_unlock(&ipu_data.lock); - /* - * Doing this - * ichan->sg[0] = ichan->sg[1] = NULL; - * you can force channel re-enable on the next tx_submit(), but - * this is dirty - think about descriptors with multiple - * sg elements. - */ - dev_warn(dev, "NFB4EOF on channel %d, ready %x, %x, cur %x\n", - chan_id, ready0, ready1, curbuf); - return IRQ_HANDLED; - } - spin_unlock(&ipu_data.lock); - - /* Other interrupts do not interfere with this channel */ - spin_lock(&ichan->lock); - if (unlikely((ichan->active_buffer && (ready1 >> chan_id) & 1) || - (!ichan->active_buffer && (ready0 >> chan_id) & 1) - )) { - spin_unlock(&ichan->lock); - dev_dbg(dev, - "IRQ with active buffer still ready on channel %x, " - "active %d, ready %x, %x!\n", chan_id, - ichan->active_buffer, ready0, ready1); - return IRQ_NONE; - } - - if (unlikely(list_empty(&ichan->queue))) { - ichan->sg[ichan->active_buffer] = NULL; - spin_unlock(&ichan->lock); - dev_err(dev, - "IRQ without queued buffers on channel %x, active %d, " - "ready %x, %x!\n", chan_id, - ichan->active_buffer, ready0, ready1); - return IRQ_NONE; - } - - /* - * active_buffer is a software flag, it shows which buffer we are - * currently expecting back from the hardware, IDMAC should be - * processing the other buffer already - */ - sg = &ichan->sg[ichan->active_buffer]; - sgnext = ichan->sg[!ichan->active_buffer]; - - if (!*sg) { - spin_unlock(&ichan->lock); - return IRQ_HANDLED; - } - - desc = list_entry(ichan->queue.next, struct idmac_tx_desc, list); - descnew = desc; - - dev_dbg(dev, "IDMAC irq %d, dma %#llx, next dma %#llx, current %d, curbuf %#x\n", - irq, (u64)sg_dma_address(*sg), - sgnext ? (u64)sg_dma_address(sgnext) : 0, - ichan->active_buffer, curbuf); - - /* Find the descriptor of sgnext */ - sgnew = idmac_sg_next(ichan, &descnew, *sg); - if (sgnext != sgnew) - dev_err(dev, "Submitted buffer %p, next buffer %p\n", sgnext, sgnew); - - /* - * if sgnext == NULL sg must be the last element in a scatterlist and - * queue must be empty - */ - if (unlikely(!sgnext)) { - if (!WARN_ON(sg_next(*sg))) - dev_dbg(dev, "Underrun on channel %x\n", chan_id); - ichan->sg[!ichan->active_buffer] = sgnew; - - if (unlikely(sgnew)) { - ipu_submit_buffer(ichan, descnew, sgnew, !ichan->active_buffer); - } else { - spin_lock(&ipu_data.lock); - ipu_ic_disable_task(&ipu_data, chan_id); - spin_unlock(&ipu_data.lock); - ichan->status = IPU_CHANNEL_READY; - /* Continue to check for complete descriptor */ - } - } - - /* Calculate and submit the next sg element */ - sgnew = idmac_sg_next(ichan, &descnew, sgnew); - - if (unlikely(!sg_next(*sg)) || !sgnext) { - /* - * Last element in scatterlist done, remove from the queue, - * _init for debugging - */ - list_del_init(&desc->list); - done = true; - } - - *sg = sgnew; - - if (likely(sgnew) && - ipu_submit_buffer(ichan, descnew, sgnew, ichan->active_buffer) < 0) { - dmaengine_desc_get_callback(&descnew->txd, &cb); - - list_del_init(&descnew->list); - spin_unlock(&ichan->lock); - - dmaengine_desc_callback_invoke(&cb, NULL); - spin_lock(&ichan->lock); - } - - /* Flip the active buffer - even if update above failed */ - ichan->active_buffer = !ichan->active_buffer; - if (done) - dma_cookie_complete(&desc->txd); - - dmaengine_desc_get_callback(&desc->txd, &cb); - - spin_unlock(&ichan->lock); - - if (done && (desc->txd.flags & DMA_PREP_INTERRUPT)) - dmaengine_desc_callback_invoke(&cb, NULL); - - return IRQ_HANDLED; -} - -static void ipu_gc_tasklet(struct tasklet_struct *t) -{ - struct ipu *ipu = from_tasklet(ipu, t, tasklet); - int i; - - for (i = 0; i < IPU_CHANNELS_NUM; i++) { - struct idmac_channel *ichan = ipu->channel + i; - struct idmac_tx_desc *desc; - unsigned long flags; - struct scatterlist *sg; - int j, k; - - for (j = 0; j < ichan->n_tx_desc; j++) { - desc = ichan->desc + j; - spin_lock_irqsave(&ichan->lock, flags); - if (async_tx_test_ack(&desc->txd)) { - list_move(&desc->list, &ichan->free_list); - for_each_sg(desc->sg, sg, desc->sg_len, k) { - if (ichan->sg[0] == sg) - ichan->sg[0] = NULL; - else if (ichan->sg[1] == sg) - ichan->sg[1] = NULL; - } - async_tx_clear_ack(&desc->txd); - } - spin_unlock_irqrestore(&ichan->lock, flags); - } - } -} - -/* Allocate and initialise a transfer descriptor. */ -static struct dma_async_tx_descriptor *idmac_prep_slave_sg(struct dma_chan *chan, - struct scatterlist *sgl, unsigned int sg_len, - enum dma_transfer_direction direction, unsigned long tx_flags, - void *context) -{ - struct idmac_channel *ichan = to_idmac_chan(chan); - struct idmac_tx_desc *desc = NULL; - struct dma_async_tx_descriptor *txd = NULL; - unsigned long flags; - - /* We only can handle these three channels so far */ - if (chan->chan_id != IDMAC_SDC_0 && chan->chan_id != IDMAC_SDC_1 && - chan->chan_id != IDMAC_IC_7) - return NULL; - - if (!is_slave_direction(direction)) { - dev_err(chan->device->dev, "Invalid DMA direction %d!\n", direction); - return NULL; - } - - mutex_lock(&ichan->chan_mutex); - - spin_lock_irqsave(&ichan->lock, flags); - if (!list_empty(&ichan->free_list)) { - desc = list_entry(ichan->free_list.next, - struct idmac_tx_desc, list); - - list_del_init(&desc->list); - - desc->sg_len = sg_len; - desc->sg = sgl; - txd = &desc->txd; - txd->flags = tx_flags; - } - spin_unlock_irqrestore(&ichan->lock, flags); - - mutex_unlock(&ichan->chan_mutex); - - tasklet_schedule(&to_ipu(to_idmac(chan->device))->tasklet); - - return txd; -} - -/* Re-select the current buffer and re-activate the channel */ -static void idmac_issue_pending(struct dma_chan *chan) -{ - struct idmac_channel *ichan = to_idmac_chan(chan); - struct idmac *idmac = to_idmac(chan->device); - struct ipu *ipu = to_ipu(idmac); - unsigned long flags; - - /* This is not always needed, but doesn't hurt either */ - spin_lock_irqsave(&ipu->lock, flags); - ipu_select_buffer(chan->chan_id, ichan->active_buffer); - spin_unlock_irqrestore(&ipu->lock, flags); - - /* - * Might need to perform some parts of initialisation from - * ipu_enable_channel(), but not all, we do not want to reset to buffer - * 0, don't need to set priority again either, but re-enabling the task - * and the channel might be a good idea. - */ -} - -static int idmac_pause(struct dma_chan *chan) -{ - struct idmac_channel *ichan = to_idmac_chan(chan); - struct idmac *idmac = to_idmac(chan->device); - struct ipu *ipu = to_ipu(idmac); - struct list_head *list, *tmp; - unsigned long flags; - - mutex_lock(&ichan->chan_mutex); - - spin_lock_irqsave(&ipu->lock, flags); - ipu_ic_disable_task(ipu, chan->chan_id); - - /* Return all descriptors into "prepared" state */ - list_for_each_safe(list, tmp, &ichan->queue) - list_del_init(list); - - ichan->sg[0] = NULL; - ichan->sg[1] = NULL; - - spin_unlock_irqrestore(&ipu->lock, flags); - - ichan->status = IPU_CHANNEL_INITIALIZED; - - mutex_unlock(&ichan->chan_mutex); - - return 0; -} - -static int __idmac_terminate_all(struct dma_chan *chan) -{ - struct idmac_channel *ichan = to_idmac_chan(chan); - struct idmac *idmac = to_idmac(chan->device); - struct ipu *ipu = to_ipu(idmac); - unsigned long flags; - int i; - - ipu_disable_channel(idmac, ichan, - ichan->status >= IPU_CHANNEL_ENABLED); - - tasklet_disable(&ipu->tasklet); - - /* ichan->queue is modified in ISR, have to spinlock */ - spin_lock_irqsave(&ichan->lock, flags); - list_splice_init(&ichan->queue, &ichan->free_list); - - if (ichan->desc) - for (i = 0; i < ichan->n_tx_desc; i++) { - struct idmac_tx_desc *desc = ichan->desc + i; - if (list_empty(&desc->list)) - /* Descriptor was prepared, but not submitted */ - list_add(&desc->list, &ichan->free_list); - - async_tx_clear_ack(&desc->txd); - } - - ichan->sg[0] = NULL; - ichan->sg[1] = NULL; - spin_unlock_irqrestore(&ichan->lock, flags); - - tasklet_enable(&ipu->tasklet); - - ichan->status = IPU_CHANNEL_INITIALIZED; - - return 0; -} - -static int idmac_terminate_all(struct dma_chan *chan) -{ - struct idmac_channel *ichan = to_idmac_chan(chan); - int ret; - - mutex_lock(&ichan->chan_mutex); - - ret = __idmac_terminate_all(chan); - - mutex_unlock(&ichan->chan_mutex); - - return ret; -} - -#ifdef DEBUG -static irqreturn_t ic_sof_irq(int irq, void *dev_id) -{ - struct idmac_channel *ichan = dev_id; - printk(KERN_DEBUG "Got SOF IRQ %d on Channel %d\n", - irq, ichan->dma_chan.chan_id); - disable_irq_nosync(irq); - return IRQ_HANDLED; -} - -static irqreturn_t ic_eof_irq(int irq, void *dev_id) -{ - struct idmac_channel *ichan = dev_id; - printk(KERN_DEBUG "Got EOF IRQ %d on Channel %d\n", - irq, ichan->dma_chan.chan_id); - disable_irq_nosync(irq); - return IRQ_HANDLED; -} - -static int ic_sof = -EINVAL, ic_eof = -EINVAL; -#endif - -static int idmac_alloc_chan_resources(struct dma_chan *chan) -{ - struct idmac_channel *ichan = to_idmac_chan(chan); - struct idmac *idmac = to_idmac(chan->device); - int ret; - - /* dmaengine.c now guarantees to only offer free channels */ - BUG_ON(chan->client_count > 1); - WARN_ON(ichan->status != IPU_CHANNEL_FREE); - - dma_cookie_init(chan); - - ret = ipu_irq_map(chan->chan_id); - if (ret < 0) - goto eimap; - - ichan->eof_irq = ret; - - /* - * Important to first disable the channel, because maybe someone - * used it before us, e.g., the bootloader - */ - ipu_disable_channel(idmac, ichan, true); - - ret = ipu_init_channel(idmac, ichan); - if (ret < 0) - goto eichan; - - ret = request_irq(ichan->eof_irq, idmac_interrupt, 0, - ichan->eof_name, ichan); - if (ret < 0) - goto erirq; - -#ifdef DEBUG - if (chan->chan_id == IDMAC_IC_7) { - ic_sof = ipu_irq_map(69); - if (ic_sof > 0) { - ret = request_irq(ic_sof, ic_sof_irq, 0, "IC SOF", ichan); - if (ret) - dev_err(&chan->dev->device, "request irq failed for IC SOF"); - } - ic_eof = ipu_irq_map(70); - if (ic_eof > 0) { - ret = request_irq(ic_eof, ic_eof_irq, 0, "IC EOF", ichan); - if (ret) - dev_err(&chan->dev->device, "request irq failed for IC EOF"); - } - } -#endif - - ichan->status = IPU_CHANNEL_INITIALIZED; - - dev_dbg(&chan->dev->device, "Found channel 0x%x, irq %d\n", - chan->chan_id, ichan->eof_irq); - - return ret; - -erirq: - ipu_uninit_channel(idmac, ichan); -eichan: - ipu_irq_unmap(chan->chan_id); -eimap: - return ret; -} - -static void idmac_free_chan_resources(struct dma_chan *chan) -{ - struct idmac_channel *ichan = to_idmac_chan(chan); - struct idmac *idmac = to_idmac(chan->device); - - mutex_lock(&ichan->chan_mutex); - - __idmac_terminate_all(chan); - - if (ichan->status > IPU_CHANNEL_FREE) { -#ifdef DEBUG - if (chan->chan_id == IDMAC_IC_7) { - if (ic_sof > 0) { - free_irq(ic_sof, ichan); - ipu_irq_unmap(69); - ic_sof = -EINVAL; - } - if (ic_eof > 0) { - free_irq(ic_eof, ichan); - ipu_irq_unmap(70); - ic_eof = -EINVAL; - } - } -#endif - free_irq(ichan->eof_irq, ichan); - ipu_irq_unmap(chan->chan_id); - } - - ichan->status = IPU_CHANNEL_FREE; - - ipu_uninit_channel(idmac, ichan); - - mutex_unlock(&ichan->chan_mutex); - - tasklet_schedule(&to_ipu(idmac)->tasklet); -} - -static enum dma_status idmac_tx_status(struct dma_chan *chan, - dma_cookie_t cookie, struct dma_tx_state *txstate) -{ - return dma_cookie_status(chan, cookie, txstate); -} - -static int __init ipu_idmac_init(struct ipu *ipu) -{ - struct idmac *idmac = &ipu->idmac; - struct dma_device *dma = &idmac->dma; - int i; - - dma_cap_set(DMA_SLAVE, dma->cap_mask); - dma_cap_set(DMA_PRIVATE, dma->cap_mask); - - /* Compulsory common fields */ - dma->dev = ipu->dev; - dma->device_alloc_chan_resources = idmac_alloc_chan_resources; - dma->device_free_chan_resources = idmac_free_chan_resources; - dma->device_tx_status = idmac_tx_status; - dma->device_issue_pending = idmac_issue_pending; - - /* Compulsory for DMA_SLAVE fields */ - dma->device_prep_slave_sg = idmac_prep_slave_sg; - dma->device_pause = idmac_pause; - dma->device_terminate_all = idmac_terminate_all; - - INIT_LIST_HEAD(&dma->channels); - for (i = 0; i < IPU_CHANNELS_NUM; i++) { - struct idmac_channel *ichan = ipu->channel + i; - struct dma_chan *dma_chan = &ichan->dma_chan; - - spin_lock_init(&ichan->lock); - mutex_init(&ichan->chan_mutex); - - ichan->status = IPU_CHANNEL_FREE; - ichan->sec_chan_en = false; - snprintf(ichan->eof_name, sizeof(ichan->eof_name), "IDMAC EOF %d", i); - - dma_chan->device = &idmac->dma; - dma_cookie_init(dma_chan); - dma_chan->chan_id = i; - list_add_tail(&dma_chan->device_node, &dma->channels); - } - - idmac_write_icreg(ipu, 0x00000070, IDMAC_CONF); - - return dma_async_device_register(&idmac->dma); -} - -static void ipu_idmac_exit(struct ipu *ipu) -{ - int i; - struct idmac *idmac = &ipu->idmac; - - for (i = 0; i < IPU_CHANNELS_NUM; i++) { - struct idmac_channel *ichan = ipu->channel + i; - - idmac_terminate_all(&ichan->dma_chan); - } - - dma_async_device_unregister(&idmac->dma); -} - -/***************************************************************************** - * IPU common probe / remove - */ - -static int __init ipu_probe(struct platform_device *pdev) -{ - struct resource *mem_ipu, *mem_ic; - int ret; - - spin_lock_init(&ipu_data.lock); - - mem_ipu = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mem_ic = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!mem_ipu || !mem_ic) - return -EINVAL; - - ipu_data.dev = &pdev->dev; - - platform_set_drvdata(pdev, &ipu_data); - - ret = platform_get_irq(pdev, 0); - if (ret < 0) - goto err_noirq; - - ipu_data.irq_fn = ret; - ret = platform_get_irq(pdev, 1); - if (ret < 0) - goto err_noirq; - - ipu_data.irq_err = ret; - - dev_dbg(&pdev->dev, "fn irq %u, err irq %u\n", - ipu_data.irq_fn, ipu_data.irq_err); - - /* Remap IPU common registers */ - ipu_data.reg_ipu = ioremap(mem_ipu->start, resource_size(mem_ipu)); - if (!ipu_data.reg_ipu) { - ret = -ENOMEM; - goto err_ioremap_ipu; - } - - /* Remap Image Converter and Image DMA Controller registers */ - ipu_data.reg_ic = ioremap(mem_ic->start, resource_size(mem_ic)); - if (!ipu_data.reg_ic) { - ret = -ENOMEM; - goto err_ioremap_ic; - } - - /* Get IPU clock */ - ipu_data.ipu_clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(ipu_data.ipu_clk)) { - ret = PTR_ERR(ipu_data.ipu_clk); - goto err_clk_get; - } - - /* Make sure IPU HSP clock is running */ - clk_prepare_enable(ipu_data.ipu_clk); - - /* Disable all interrupts */ - idmac_write_ipureg(&ipu_data, 0, IPU_INT_CTRL_1); - idmac_write_ipureg(&ipu_data, 0, IPU_INT_CTRL_2); - idmac_write_ipureg(&ipu_data, 0, IPU_INT_CTRL_3); - idmac_write_ipureg(&ipu_data, 0, IPU_INT_CTRL_4); - idmac_write_ipureg(&ipu_data, 0, IPU_INT_CTRL_5); - - dev_dbg(&pdev->dev, "%s @ 0x%08lx, fn irq %u, err irq %u\n", pdev->name, - (unsigned long)mem_ipu->start, ipu_data.irq_fn, ipu_data.irq_err); - - ret = ipu_irq_attach_irq(&ipu_data, pdev); - if (ret < 0) - goto err_attach_irq; - - /* Initialize DMA engine */ - ret = ipu_idmac_init(&ipu_data); - if (ret < 0) - goto err_idmac_init; - - tasklet_setup(&ipu_data.tasklet, ipu_gc_tasklet); - - ipu_data.dev = &pdev->dev; - - dev_dbg(ipu_data.dev, "IPU initialized\n"); - - return 0; - -err_idmac_init: -err_attach_irq: - ipu_irq_detach_irq(&ipu_data, pdev); - clk_disable_unprepare(ipu_data.ipu_clk); - clk_put(ipu_data.ipu_clk); -err_clk_get: - iounmap(ipu_data.reg_ic); -err_ioremap_ic: - iounmap(ipu_data.reg_ipu); -err_ioremap_ipu: -err_noirq: - dev_err(&pdev->dev, "Failed to probe IPU: %d\n", ret); - return ret; -} - -static int ipu_remove(struct platform_device *pdev) -{ - struct ipu *ipu = platform_get_drvdata(pdev); - - ipu_idmac_exit(ipu); - ipu_irq_detach_irq(ipu, pdev); - clk_disable_unprepare(ipu->ipu_clk); - clk_put(ipu->ipu_clk); - iounmap(ipu->reg_ic); - iounmap(ipu->reg_ipu); - tasklet_kill(&ipu->tasklet); - - return 0; -} - -/* - * We need two MEM resources - with IPU-common and Image Converter registers, - * including PF_CONF and IDMAC_* registers, and two IRQs - function and error - */ -static struct platform_driver ipu_platform_driver = { - .driver = { - .name = "ipu-core", - }, - .remove = ipu_remove, -}; - -static int __init ipu_init(void) -{ - return platform_driver_probe(&ipu_platform_driver, ipu_probe); -} -subsys_initcall(ipu_init); - -MODULE_DESCRIPTION("IPU core driver"); -MODULE_AUTHOR("Guennadi Liakhovetski "); -MODULE_ALIAS("platform:ipu-core"); diff --git a/drivers/dma/ipu/ipu_intern.h b/drivers/dma/ipu/ipu_intern.h deleted file mode 100644 index e7ec1dec3edfd..0000000000000 --- a/drivers/dma/ipu/ipu_intern.h +++ /dev/null @@ -1,173 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2008 - * Guennadi Liakhovetski, DENX Software Engineering, - * - * Copyright (C) 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. - */ - -#ifndef _IPU_INTERN_H_ -#define _IPU_INTERN_H_ - -#include -#include -#include - -/* IPU Common registers */ -#define IPU_CONF 0x00 -#define IPU_CHA_BUF0_RDY 0x04 -#define IPU_CHA_BUF1_RDY 0x08 -#define IPU_CHA_DB_MODE_SEL 0x0C -#define IPU_CHA_CUR_BUF 0x10 -#define IPU_FS_PROC_FLOW 0x14 -#define IPU_FS_DISP_FLOW 0x18 -#define IPU_TASKS_STAT 0x1C -#define IPU_IMA_ADDR 0x20 -#define IPU_IMA_DATA 0x24 -#define IPU_INT_CTRL_1 0x28 -#define IPU_INT_CTRL_2 0x2C -#define IPU_INT_CTRL_3 0x30 -#define IPU_INT_CTRL_4 0x34 -#define IPU_INT_CTRL_5 0x38 -#define IPU_INT_STAT_1 0x3C -#define IPU_INT_STAT_2 0x40 -#define IPU_INT_STAT_3 0x44 -#define IPU_INT_STAT_4 0x48 -#define IPU_INT_STAT_5 0x4C -#define IPU_BRK_CTRL_1 0x50 -#define IPU_BRK_CTRL_2 0x54 -#define IPU_BRK_STAT 0x58 -#define IPU_DIAGB_CTRL 0x5C - -/* IPU_CONF Register bits */ -#define IPU_CONF_CSI_EN 0x00000001 -#define IPU_CONF_IC_EN 0x00000002 -#define IPU_CONF_ROT_EN 0x00000004 -#define IPU_CONF_PF_EN 0x00000008 -#define IPU_CONF_SDC_EN 0x00000010 -#define IPU_CONF_ADC_EN 0x00000020 -#define IPU_CONF_DI_EN 0x00000040 -#define IPU_CONF_DU_EN 0x00000080 -#define IPU_CONF_PXL_ENDIAN 0x00000100 - -/* Image Converter Registers */ -#define IC_CONF 0x88 -#define IC_PRP_ENC_RSC 0x8C -#define IC_PRP_VF_RSC 0x90 -#define IC_PP_RSC 0x94 -#define IC_CMBP_1 0x98 -#define IC_CMBP_2 0x9C -#define PF_CONF 0xA0 -#define IDMAC_CONF 0xA4 -#define IDMAC_CHA_EN 0xA8 -#define IDMAC_CHA_PRI 0xAC -#define IDMAC_CHA_BUSY 0xB0 - -/* Image Converter Register bits */ -#define IC_CONF_PRPENC_EN 0x00000001 -#define IC_CONF_PRPENC_CSC1 0x00000002 -#define IC_CONF_PRPENC_ROT_EN 0x00000004 -#define IC_CONF_PRPVF_EN 0x00000100 -#define IC_CONF_PRPVF_CSC1 0x00000200 -#define IC_CONF_PRPVF_CSC2 0x00000400 -#define IC_CONF_PRPVF_CMB 0x00000800 -#define IC_CONF_PRPVF_ROT_EN 0x00001000 -#define IC_CONF_PP_EN 0x00010000 -#define IC_CONF_PP_CSC1 0x00020000 -#define IC_CONF_PP_CSC2 0x00040000 -#define IC_CONF_PP_CMB 0x00080000 -#define IC_CONF_PP_ROT_EN 0x00100000 -#define IC_CONF_IC_GLB_LOC_A 0x10000000 -#define IC_CONF_KEY_COLOR_EN 0x20000000 -#define IC_CONF_RWS_EN 0x40000000 -#define IC_CONF_CSI_MEM_WR_EN 0x80000000 - -#define IDMA_CHAN_INVALID 0x000000FF -#define IDMA_IC_0 0x00000001 -#define IDMA_IC_1 0x00000002 -#define IDMA_IC_2 0x00000004 -#define IDMA_IC_3 0x00000008 -#define IDMA_IC_4 0x00000010 -#define IDMA_IC_5 0x00000020 -#define IDMA_IC_6 0x00000040 -#define IDMA_IC_7 0x00000080 -#define IDMA_IC_8 0x00000100 -#define IDMA_IC_9 0x00000200 -#define IDMA_IC_10 0x00000400 -#define IDMA_IC_11 0x00000800 -#define IDMA_IC_12 0x00001000 -#define IDMA_IC_13 0x00002000 -#define IDMA_SDC_BG 0x00004000 -#define IDMA_SDC_FG 0x00008000 -#define IDMA_SDC_MASK 0x00010000 -#define IDMA_SDC_PARTIAL 0x00020000 -#define IDMA_ADC_SYS1_WR 0x00040000 -#define IDMA_ADC_SYS2_WR 0x00080000 -#define IDMA_ADC_SYS1_CMD 0x00100000 -#define IDMA_ADC_SYS2_CMD 0x00200000 -#define IDMA_ADC_SYS1_RD 0x00400000 -#define IDMA_ADC_SYS2_RD 0x00800000 -#define IDMA_PF_QP 0x01000000 -#define IDMA_PF_BSP 0x02000000 -#define IDMA_PF_Y_IN 0x04000000 -#define IDMA_PF_U_IN 0x08000000 -#define IDMA_PF_V_IN 0x10000000 -#define IDMA_PF_Y_OUT 0x20000000 -#define IDMA_PF_U_OUT 0x40000000 -#define IDMA_PF_V_OUT 0x80000000 - -#define TSTAT_PF_H264_PAUSE 0x00000001 -#define TSTAT_CSI2MEM_MASK 0x0000000C -#define TSTAT_CSI2MEM_OFFSET 2 -#define TSTAT_VF_MASK 0x00000600 -#define TSTAT_VF_OFFSET 9 -#define TSTAT_VF_ROT_MASK 0x000C0000 -#define TSTAT_VF_ROT_OFFSET 18 -#define TSTAT_ENC_MASK 0x00000180 -#define TSTAT_ENC_OFFSET 7 -#define TSTAT_ENC_ROT_MASK 0x00030000 -#define TSTAT_ENC_ROT_OFFSET 16 -#define TSTAT_PP_MASK 0x00001800 -#define TSTAT_PP_OFFSET 11 -#define TSTAT_PP_ROT_MASK 0x00300000 -#define TSTAT_PP_ROT_OFFSET 20 -#define TSTAT_PF_MASK 0x00C00000 -#define TSTAT_PF_OFFSET 22 -#define TSTAT_ADCSYS1_MASK 0x03000000 -#define TSTAT_ADCSYS1_OFFSET 24 -#define TSTAT_ADCSYS2_MASK 0x0C000000 -#define TSTAT_ADCSYS2_OFFSET 26 - -#define TASK_STAT_IDLE 0 -#define TASK_STAT_ACTIVE 1 -#define TASK_STAT_WAIT4READY 2 - -struct idmac { - struct dma_device dma; -}; - -struct ipu { - void __iomem *reg_ipu; - void __iomem *reg_ic; - unsigned int irq_fn; /* IPU Function IRQ to the CPU */ - unsigned int irq_err; /* IPU Error IRQ to the CPU */ - unsigned int irq_base; /* Beginning of the IPU IRQ range */ - unsigned long channel_init_mask; - spinlock_t lock; - struct clk *ipu_clk; - struct device *dev; - struct idmac idmac; - struct idmac_channel channel[IPU_CHANNELS_NUM]; - struct tasklet_struct tasklet; -}; - -#define to_idmac(d) container_of(d, struct idmac, dma) - -extern int ipu_irq_attach_irq(struct ipu *ipu, struct platform_device *dev); -extern void ipu_irq_detach_irq(struct ipu *ipu, struct platform_device *dev); - -extern bool ipu_irq_status(uint32_t irq); -extern int ipu_irq_map(unsigned int source); -extern int ipu_irq_unmap(unsigned int source); - -#endif diff --git a/drivers/dma/ipu/ipu_irq.c b/drivers/dma/ipu/ipu_irq.c deleted file mode 100644 index 97d9a6f04f2a2..0000000000000 --- a/drivers/dma/ipu/ipu_irq.c +++ /dev/null @@ -1,367 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2008 - * Guennadi Liakhovetski, DENX Software Engineering, - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ipu_intern.h" - -/* - * Register read / write - shall be inlined by the compiler - */ -static u32 ipu_read_reg(struct ipu *ipu, unsigned long reg) -{ - return __raw_readl(ipu->reg_ipu + reg); -} - -static void ipu_write_reg(struct ipu *ipu, u32 value, unsigned long reg) -{ - __raw_writel(value, ipu->reg_ipu + reg); -} - - -/* - * IPU IRQ chip driver - */ - -#define IPU_IRQ_NR_FN_BANKS 3 -#define IPU_IRQ_NR_ERR_BANKS 2 -#define IPU_IRQ_NR_BANKS (IPU_IRQ_NR_FN_BANKS + IPU_IRQ_NR_ERR_BANKS) - -struct ipu_irq_bank { - unsigned int control; - unsigned int status; - struct ipu *ipu; -}; - -static struct ipu_irq_bank irq_bank[IPU_IRQ_NR_BANKS] = { - /* 3 groups of functional interrupts */ - { - .control = IPU_INT_CTRL_1, - .status = IPU_INT_STAT_1, - }, { - .control = IPU_INT_CTRL_2, - .status = IPU_INT_STAT_2, - }, { - .control = IPU_INT_CTRL_3, - .status = IPU_INT_STAT_3, - }, - /* 2 groups of error interrupts */ - { - .control = IPU_INT_CTRL_4, - .status = IPU_INT_STAT_4, - }, { - .control = IPU_INT_CTRL_5, - .status = IPU_INT_STAT_5, - }, -}; - -struct ipu_irq_map { - unsigned int irq; - int source; - struct ipu_irq_bank *bank; - struct ipu *ipu; -}; - -static struct ipu_irq_map irq_map[CONFIG_MX3_IPU_IRQS]; -/* Protects allocations from the above array of maps */ -static DEFINE_MUTEX(map_lock); -/* Protects register accesses and individual mappings */ -static DEFINE_RAW_SPINLOCK(bank_lock); - -static struct ipu_irq_map *src2map(unsigned int src) -{ - int i; - - for (i = 0; i < CONFIG_MX3_IPU_IRQS; i++) - if (irq_map[i].source == src) - return irq_map + i; - - return NULL; -} - -static void ipu_irq_unmask(struct irq_data *d) -{ - struct ipu_irq_map *map = irq_data_get_irq_chip_data(d); - struct ipu_irq_bank *bank; - uint32_t reg; - unsigned long lock_flags; - - raw_spin_lock_irqsave(&bank_lock, lock_flags); - - bank = map->bank; - if (!bank) { - raw_spin_unlock_irqrestore(&bank_lock, lock_flags); - pr_err("IPU: %s(%u) - unmapped!\n", __func__, d->irq); - return; - } - - reg = ipu_read_reg(bank->ipu, bank->control); - reg |= (1UL << (map->source & 31)); - ipu_write_reg(bank->ipu, reg, bank->control); - - raw_spin_unlock_irqrestore(&bank_lock, lock_flags); -} - -static void ipu_irq_mask(struct irq_data *d) -{ - struct ipu_irq_map *map = irq_data_get_irq_chip_data(d); - struct ipu_irq_bank *bank; - uint32_t reg; - unsigned long lock_flags; - - raw_spin_lock_irqsave(&bank_lock, lock_flags); - - bank = map->bank; - if (!bank) { - raw_spin_unlock_irqrestore(&bank_lock, lock_flags); - pr_err("IPU: %s(%u) - unmapped!\n", __func__, d->irq); - return; - } - - reg = ipu_read_reg(bank->ipu, bank->control); - reg &= ~(1UL << (map->source & 31)); - ipu_write_reg(bank->ipu, reg, bank->control); - - raw_spin_unlock_irqrestore(&bank_lock, lock_flags); -} - -static void ipu_irq_ack(struct irq_data *d) -{ - struct ipu_irq_map *map = irq_data_get_irq_chip_data(d); - struct ipu_irq_bank *bank; - unsigned long lock_flags; - - raw_spin_lock_irqsave(&bank_lock, lock_flags); - - bank = map->bank; - if (!bank) { - raw_spin_unlock_irqrestore(&bank_lock, lock_flags); - pr_err("IPU: %s(%u) - unmapped!\n", __func__, d->irq); - return; - } - - ipu_write_reg(bank->ipu, 1UL << (map->source & 31), bank->status); - raw_spin_unlock_irqrestore(&bank_lock, lock_flags); -} - -/** - * ipu_irq_status() - returns the current interrupt status of the specified IRQ. - * @irq: interrupt line to get status for. - * @return: true if the interrupt is pending/asserted or false if the - * interrupt is not pending. - */ -bool ipu_irq_status(unsigned int irq) -{ - struct ipu_irq_map *map = irq_get_chip_data(irq); - struct ipu_irq_bank *bank; - unsigned long lock_flags; - bool ret; - - raw_spin_lock_irqsave(&bank_lock, lock_flags); - bank = map->bank; - ret = bank && ipu_read_reg(bank->ipu, bank->status) & - (1UL << (map->source & 31)); - raw_spin_unlock_irqrestore(&bank_lock, lock_flags); - - return ret; -} - -/** - * ipu_irq_map() - map an IPU interrupt source to an IRQ number - * @source: interrupt source bit position (see below) - * @return: mapped IRQ number or negative error code - * - * The source parameter has to be explained further. On i.MX31 IPU has 137 IRQ - * sources, they are broken down in 5 32-bit registers, like 32, 32, 24, 32, 17. - * However, the source argument of this function is not the sequence number of - * the possible IRQ, but rather its bit position. So, first interrupt in fourth - * register has source number 96, and not 88. This makes calculations easier, - * and also provides forward compatibility with any future IPU implementations - * with any interrupt bit assignments. - */ -int ipu_irq_map(unsigned int source) -{ - int i, ret = -ENOMEM; - struct ipu_irq_map *map; - - might_sleep(); - - mutex_lock(&map_lock); - map = src2map(source); - if (map) { - pr_err("IPU: Source %u already mapped to IRQ %u\n", source, map->irq); - ret = -EBUSY; - goto out; - } - - for (i = 0; i < CONFIG_MX3_IPU_IRQS; i++) { - if (irq_map[i].source < 0) { - unsigned long lock_flags; - - raw_spin_lock_irqsave(&bank_lock, lock_flags); - irq_map[i].source = source; - irq_map[i].bank = irq_bank + source / 32; - raw_spin_unlock_irqrestore(&bank_lock, lock_flags); - - ret = irq_map[i].irq; - pr_debug("IPU: mapped source %u to IRQ %u\n", - source, ret); - break; - } - } -out: - mutex_unlock(&map_lock); - - if (ret < 0) - pr_err("IPU: couldn't map source %u: %d\n", source, ret); - - return ret; -} - -/** - * ipu_irq_unmap() - unmap an IPU interrupt source - * @source: interrupt source bit position (see ipu_irq_map()) - * @return: 0 or negative error code - */ -int ipu_irq_unmap(unsigned int source) -{ - int i, ret = -EINVAL; - - might_sleep(); - - mutex_lock(&map_lock); - for (i = 0; i < CONFIG_MX3_IPU_IRQS; i++) { - if (irq_map[i].source == source) { - unsigned long lock_flags; - - pr_debug("IPU: unmapped source %u from IRQ %u\n", - source, irq_map[i].irq); - - raw_spin_lock_irqsave(&bank_lock, lock_flags); - irq_map[i].source = -EINVAL; - irq_map[i].bank = NULL; - raw_spin_unlock_irqrestore(&bank_lock, lock_flags); - - ret = 0; - break; - } - } - mutex_unlock(&map_lock); - - return ret; -} - -/* Chained IRQ handler for IPU function and error interrupt */ -static void ipu_irq_handler(struct irq_desc *desc) -{ - struct ipu *ipu = irq_desc_get_handler_data(desc); - u32 status; - int i, line; - - for (i = 0; i < IPU_IRQ_NR_BANKS; i++) { - struct ipu_irq_bank *bank = irq_bank + i; - - raw_spin_lock(&bank_lock); - status = ipu_read_reg(ipu, bank->status); - /* - * Don't think we have to clear all interrupts here, they will - * be acked by ->handle_irq() (handle_level_irq). However, we - * might want to clear unhandled interrupts after the loop... - */ - status &= ipu_read_reg(ipu, bank->control); - raw_spin_unlock(&bank_lock); - while ((line = ffs(status))) { - struct ipu_irq_map *map; - unsigned int irq; - - line--; - status &= ~(1UL << line); - - raw_spin_lock(&bank_lock); - map = src2map(32 * i + line); - if (!map) { - raw_spin_unlock(&bank_lock); - pr_err("IPU: Interrupt on unmapped source %u bank %d\n", - line, i); - continue; - } - irq = map->irq; - raw_spin_unlock(&bank_lock); - generic_handle_irq(irq); - } - } -} - -static struct irq_chip ipu_irq_chip = { - .name = "ipu_irq", - .irq_ack = ipu_irq_ack, - .irq_mask = ipu_irq_mask, - .irq_unmask = ipu_irq_unmask, -}; - -/* Install the IRQ handler */ -int __init ipu_irq_attach_irq(struct ipu *ipu, struct platform_device *dev) -{ - unsigned int irq, i; - int irq_base = irq_alloc_descs(-1, 0, CONFIG_MX3_IPU_IRQS, - numa_node_id()); - - if (irq_base < 0) - return irq_base; - - for (i = 0; i < IPU_IRQ_NR_BANKS; i++) - irq_bank[i].ipu = ipu; - - for (i = 0; i < CONFIG_MX3_IPU_IRQS; i++) { - int ret; - - irq = irq_base + i; - ret = irq_set_chip(irq, &ipu_irq_chip); - if (ret < 0) - return ret; - ret = irq_set_chip_data(irq, irq_map + i); - if (ret < 0) - return ret; - irq_map[i].ipu = ipu; - irq_map[i].irq = irq; - irq_map[i].source = -EINVAL; - irq_set_handler(irq, handle_level_irq); - irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); - } - - irq_set_chained_handler_and_data(ipu->irq_fn, ipu_irq_handler, ipu); - - irq_set_chained_handler_and_data(ipu->irq_err, ipu_irq_handler, ipu); - - ipu->irq_base = irq_base; - - return 0; -} - -void ipu_irq_detach_irq(struct ipu *ipu, struct platform_device *dev) -{ - unsigned int irq, irq_base; - - irq_base = ipu->irq_base; - - irq_set_chained_handler_and_data(ipu->irq_fn, NULL, NULL); - - irq_set_chained_handler_and_data(ipu->irq_err, NULL, NULL); - - for (irq = irq_base; irq < irq_base + CONFIG_MX3_IPU_IRQS; irq++) { - irq_set_status_flags(irq, IRQ_NOREQUEST); - irq_set_chip(irq, NULL); - irq_set_chip_data(irq, NULL); - } -} -- GitLab From cae701b9ccf128edea26982f73178087fc3ad180 Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Mon, 3 Jul 2023 16:52:37 +0200 Subject: [PATCH 0639/3445] dmaengine:idxd: Use local64_try_cmpxchg in perfmon_pmu_event_update Use local64_try_cmpxchg instead of local64_cmpxchg (*ptr, old, new) == old in perfmon_pmu_event_update. x86 CMPXCHG instruction returns success in ZF flag, so this change saves a compare after cmpxchg (and related move instruction in front of cmpxchg). Also, try_cmpxchg implicitly assigns old *ptr value to "old" when cmpxchg fails. There is no need to re-read the value in the loop. No functional change intended. Cc: Fenghua Yu Cc: Dave Jiang Cc: Vinod Koul Signed-off-by: Uros Bizjak Reviewed-by: Tom Zanussi Link: https://lore.kernel.org/r/20230703145346.5206-1-ubizjak@gmail.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/perfmon.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/dma/idxd/perfmon.c b/drivers/dma/idxd/perfmon.c index d73004f47cf4b..fdda6d6042629 100644 --- a/drivers/dma/idxd/perfmon.c +++ b/drivers/dma/idxd/perfmon.c @@ -245,12 +245,11 @@ static void perfmon_pmu_event_update(struct perf_event *event) int shift = 64 - idxd->idxd_pmu->counter_width; struct hw_perf_event *hwc = &event->hw; + prev_raw_count = local64_read(&hwc->prev_count); do { - prev_raw_count = local64_read(&hwc->prev_count); new_raw_count = perfmon_pmu_read_counter(event); - } while (local64_cmpxchg(&hwc->prev_count, prev_raw_count, - new_raw_count) != prev_raw_count); - + } while (!local64_try_cmpxchg(&hwc->prev_count, + &prev_raw_count, new_raw_count)); n = (new_raw_count << shift); p = (prev_raw_count << shift); -- GitLab From 97b1185fe54c8ce94104e3c7fa4ee0bbedd85920 Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Wed, 12 Jul 2023 10:44:35 -0700 Subject: [PATCH 0640/3445] dmaengine: idxd: Simplify WQ attribute visibility checks The functions that check if WQ attributes are invisible are almost duplicate. Define a helper to simplify these functions and future WQ attribute visibility checks as well. Signed-off-by: Fenghua Yu Reviewed-by: Dave Jiang Link: https://lore.kernel.org/r/20230712174436.3435088-1-fenghua.yu@intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/sysfs.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index b6a0a12412afd..36a30957ac9a3 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -1288,12 +1288,9 @@ static struct attribute *idxd_wq_attributes[] = { NULL, }; -static bool idxd_wq_attr_op_config_invisible(struct attribute *attr, - struct idxd_device *idxd) -{ - return attr == &dev_attr_wq_op_config.attr && - !idxd->hw.wq_cap.op_config; -} +/* A WQ attr is invisible if the feature is not supported in WQCAP. */ +#define idxd_wq_attr_invisible(name, cap_field, a, idxd) \ + ((a) == &dev_attr_wq_##name.attr && !(idxd)->hw.wq_cap.cap_field) static bool idxd_wq_attr_max_batch_size_invisible(struct attribute *attr, struct idxd_device *idxd) @@ -1303,13 +1300,6 @@ static bool idxd_wq_attr_max_batch_size_invisible(struct attribute *attr, idxd->data->type == IDXD_TYPE_IAX; } -static bool idxd_wq_attr_wq_prs_disable_invisible(struct attribute *attr, - struct idxd_device *idxd) -{ - return attr == &dev_attr_wq_prs_disable.attr && - !idxd->hw.wq_cap.wq_prs_support; -} - static umode_t idxd_wq_attr_visible(struct kobject *kobj, struct attribute *attr, int n) { @@ -1317,13 +1307,13 @@ static umode_t idxd_wq_attr_visible(struct kobject *kobj, struct idxd_wq *wq = confdev_to_wq(dev); struct idxd_device *idxd = wq->idxd; - if (idxd_wq_attr_op_config_invisible(attr, idxd)) + if (idxd_wq_attr_invisible(op_config, op_config, attr, idxd)) return 0; if (idxd_wq_attr_max_batch_size_invisible(attr, idxd)) return 0; - if (idxd_wq_attr_wq_prs_disable_invisible(attr, idxd)) + if (idxd_wq_attr_invisible(prs_disable, wq_prs_support, attr, idxd)) return 0; return attr->mode; -- GitLab From 62b41b656666d2d35890124df5ef0881fe6d6769 Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Wed, 12 Jul 2023 10:44:36 -0700 Subject: [PATCH 0641/3445] dmaengine: idxd: Expose ATS disable knob only when WQ ATS is supported WQ Advanced Translation Service (ATS) can be controlled only when WQ ATS is supported. The sysfs ATS disable knob should be visible only when the features is supported. Signed-off-by: Fenghua Yu Reviewed-by: Dave Jiang Link: https://lore.kernel.org/r/20230712174436.3435088-2-fenghua.yu@intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/sysfs.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index 36a30957ac9a3..d16c16445c4f9 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -1088,16 +1088,12 @@ static ssize_t wq_ats_disable_store(struct device *dev, struct device_attribute const char *buf, size_t count) { struct idxd_wq *wq = confdev_to_wq(dev); - struct idxd_device *idxd = wq->idxd; bool ats_dis; int rc; if (wq->state != IDXD_WQ_DISABLED) return -EPERM; - if (!idxd->hw.wq_cap.wq_ats_support) - return -EOPNOTSUPP; - rc = kstrtobool(buf, &ats_dis); if (rc < 0) return rc; @@ -1316,6 +1312,9 @@ static umode_t idxd_wq_attr_visible(struct kobject *kobj, if (idxd_wq_attr_invisible(prs_disable, wq_prs_support, attr, idxd)) return 0; + if (idxd_wq_attr_invisible(ats_disable, wq_ats_support, attr, idxd)) + return 0; + return attr->mode; } -- GitLab From 897500c7ea91702966adb9b412fa39400b4edee6 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 18 Jul 2023 08:31:35 -0600 Subject: [PATCH 0642/3445] dmaengine: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230718143138.1066177-1-robh@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/apple-admac.c | 3 ++- drivers/dma/at_hdmac.c | 2 +- drivers/dma/bcm-sba-raid.c | 4 +++- drivers/dma/bestcomm/bestcomm.c | 3 +-- drivers/dma/dma-jz4780.c | 1 - drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 1 - drivers/dma/dw/rzn1-dmamux.c | 4 +++- drivers/dma/fsl-qdma.c | 4 ++-- drivers/dma/fsl_raid.c | 3 ++- drivers/dma/fsldma.c | 3 ++- drivers/dma/img-mdc-dma.c | 1 - drivers/dma/imx-dma.c | 2 +- drivers/dma/imx-sdma.c | 1 - drivers/dma/lpc18xx-dmamux.c | 4 +++- drivers/dma/mediatek/mtk-cqdma.c | 1 - drivers/dma/mediatek/mtk-hsdma.c | 1 - drivers/dma/mediatek/mtk-uart-apdma.c | 1 - drivers/dma/mpc512x_dma.c | 4 ++-- drivers/dma/mxs-dma.c | 1 - drivers/dma/nbpfaxi.c | 1 - drivers/dma/owl-dma.c | 3 ++- drivers/dma/ppc4xx/adma.c | 2 +- drivers/dma/qcom/hidma.c | 2 +- drivers/dma/sh/shdmac.c | 1 - drivers/dma/sprd-dma.c | 2 +- drivers/dma/stm32-dmamux.c | 4 +++- drivers/dma/stm32-mdma.c | 1 - drivers/dma/sun6i-dma.c | 2 +- drivers/dma/tegra186-gpc-dma.c | 2 +- drivers/dma/tegra20-apb-dma.c | 1 - drivers/dma/tegra210-adma.c | 3 ++- drivers/dma/ti/dma-crossbar.c | 5 +++-- drivers/dma/ti/edma.c | 1 - drivers/dma/ti/k3-udma-private.c | 2 ++ drivers/dma/ti/k3-udma.c | 1 - drivers/dma/ti/omap-dma.c | 2 +- drivers/dma/xgene-dma.c | 3 ++- drivers/dma/xilinx/xilinx_dma.c | 4 ++-- drivers/dma/xilinx/zynqmp_dma.c | 3 ++- 39 files changed, 46 insertions(+), 43 deletions(-) diff --git a/drivers/dma/apple-admac.c b/drivers/dma/apple-admac.c index 4cf8da77bdd91..3af795635c5ce 100644 --- a/drivers/dma/apple-admac.c +++ b/drivers/dma/apple-admac.c @@ -10,8 +10,9 @@ #include #include #include -#include +#include #include +#include #include #include #include diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index ee3a219e3a897..b2876f67471fe 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/dma/bcm-sba-raid.c b/drivers/dma/bcm-sba-raid.c index 064761289a738..94ea35330eb5c 100644 --- a/drivers/dma/bcm-sba-raid.c +++ b/drivers/dma/bcm-sba-raid.c @@ -35,7 +35,9 @@ #include #include #include -#include +#include +#include +#include #include #include diff --git a/drivers/dma/bestcomm/bestcomm.c b/drivers/dma/bestcomm/bestcomm.c index eabbcfcaa7cba..80096f94032dc 100644 --- a/drivers/dma/bestcomm/bestcomm.c +++ b/drivers/dma/bestcomm/bestcomm.c @@ -14,9 +14,8 @@ #include #include #include -#include #include -#include +#include #include #include #include diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index 9c1a6e9a9c030..adbd47bd6adfe 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c index 796b6caf0babe..dd02f84e404d0 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/dma/dw/rzn1-dmamux.c b/drivers/dma/dw/rzn1-dmamux.c index f9912c3dd4d7c..4fb8508419dbd 100644 --- a/drivers/dma/dw/rzn1-dmamux.c +++ b/drivers/dma/dw/rzn1-dmamux.c @@ -5,8 +5,10 @@ * Based on TI crossbar driver written by Peter Ujfalusi */ #include -#include +#include #include +#include +#include #include #include #include diff --git a/drivers/dma/fsl-qdma.c b/drivers/dma/fsl-qdma.c index eddb2688f2340..a8cc8a4bc6102 100644 --- a/drivers/dma/fsl-qdma.c +++ b/drivers/dma/fsl-qdma.c @@ -13,10 +13,10 @@ #include #include -#include -#include +#include #include #include +#include #include "virt-dma.h" #include "fsldma.h" diff --git a/drivers/dma/fsl_raid.c b/drivers/dma/fsl_raid.c index fdf3500d96a9e..0b9ca93ce3dca 100644 --- a/drivers/dma/fsl_raid.c +++ b/drivers/dma/fsl_raid.c @@ -60,9 +60,10 @@ */ #include #include +#include #include -#include #include +#include #include #include #include diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index f8459cc5315df..ddcf736d283d8 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -28,9 +28,10 @@ #include #include #include +#include #include #include -#include +#include #include #include "dmaengine.h" #include "fsldma.h" diff --git a/drivers/dma/img-mdc-dma.c b/drivers/dma/img-mdc-dma.c index ad084552640ff..9be0d3226e199 100644 --- a/drivers/dma/img-mdc-dma.c +++ b/drivers/dma/img-mdc-dma.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index f040751690af1..114f254b9f505 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 7a912f90c2a9a..51012bd399002 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include diff --git a/drivers/dma/lpc18xx-dmamux.c b/drivers/dma/lpc18xx-dmamux.c index df98cae8792ba..2b6436f4b1937 100644 --- a/drivers/dma/lpc18xx-dmamux.c +++ b/drivers/dma/lpc18xx-dmamux.c @@ -12,8 +12,10 @@ #include #include #include -#include +#include #include +#include +#include #include #include diff --git a/drivers/dma/mediatek/mtk-cqdma.c b/drivers/dma/mediatek/mtk-cqdma.c index 9ae92b8940efe..324b7387b1b92 100644 --- a/drivers/dma/mediatek/mtk-cqdma.c +++ b/drivers/dma/mediatek/mtk-cqdma.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/dma/mediatek/mtk-hsdma.c b/drivers/dma/mediatek/mtk-hsdma.c index 69cc61c0b262b..64120767d9838 100644 --- a/drivers/dma/mediatek/mtk-hsdma.c +++ b/drivers/dma/mediatek/mtk-hsdma.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/dma/mediatek/mtk-uart-apdma.c b/drivers/dma/mediatek/mtk-uart-apdma.c index 92864c9371a31..c51dc017b48a8 100644 --- a/drivers/dma/mediatek/mtk-uart-apdma.c +++ b/drivers/dma/mediatek/mtk-uart-apdma.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c index 4a51fdbf5aa9c..1104017320b88 100644 --- a/drivers/dma/mpc512x_dma.c +++ b/drivers/dma/mpc512x_dma.c @@ -36,11 +36,11 @@ #include #include #include +#include #include -#include #include #include -#include +#include #include diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c index acc4d53e4630d..cfb9962417ef6 100644 --- a/drivers/dma/mxs-dma.c +++ b/drivers/dma/mxs-dma.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/dma/nbpfaxi.c b/drivers/dma/nbpfaxi.c index e72e8c10355ea..0b2f96fd8bf0c 100644 --- a/drivers/dma/nbpfaxi.c +++ b/drivers/dma/nbpfaxi.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/dma/owl-dma.c b/drivers/dma/owl-dma.c index 95a462a1f5111..e745f0c67094b 100644 --- a/drivers/dma/owl-dma.c +++ b/drivers/dma/owl-dma.c @@ -20,8 +20,9 @@ #include #include #include -#include +#include #include +#include #include #include "virt-dma.h" diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c index 686c270ef7100..f9b82dff33871 100644 --- a/drivers/dma/ppc4xx/adma.c +++ b/drivers/dma/ppc4xx/adma.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include "adma.h" diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c index b5e3633e6a5e1..834ae519c15de 100644 --- a/drivers/dma/qcom/hidma.c +++ b/drivers/dma/qcom/hidma.c @@ -45,12 +45,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include #include diff --git a/drivers/dma/sh/shdmac.c b/drivers/dma/sh/shdmac.c index fb3c56a416d15..00067b29e2322 100644 --- a/drivers/dma/sh/shdmac.c +++ b/drivers/dma/sh/shdmac.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index 2b639adb48ba5..168aa0bd73a0d 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/dma/stm32-dmamux.c b/drivers/dma/stm32-dmamux.c index e415bd9f4f2b6..8d77e2a7939a0 100644 --- a/drivers/dma/stm32-dmamux.c +++ b/drivers/dma/stm32-dmamux.c @@ -15,8 +15,10 @@ #include #include #include -#include +#include #include +#include +#include #include #include #include diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c index 1d0e9dd72ab39..0de234022c6d6 100644 --- a/drivers/dma/stm32-mdma.c +++ b/drivers/dma/stm32-mdma.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c index ebfd29888b2f5..2469efddf5401 100644 --- a/drivers/dma/sun6i-dma.c +++ b/drivers/dma/sun6i-dma.c @@ -14,8 +14,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c index 8f67f453a4922..33b1010011009 100644 --- a/drivers/dma/tegra186-gpc-dma.c +++ b/drivers/dma/tegra186-gpc-dma.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index cc6b91f489799..063022f9df763 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c index b970040360717..e557bada15107 100644 --- a/drivers/dma/tegra210-adma.c +++ b/drivers/dma/tegra210-adma.c @@ -8,9 +8,10 @@ #include #include #include -#include +#include #include #include +#include #include #include diff --git a/drivers/dma/ti/dma-crossbar.c b/drivers/dma/ti/dma-crossbar.c index f744ddbbbad7f..7f17ee87a6dce 100644 --- a/drivers/dma/ti/dma-crossbar.c +++ b/drivers/dma/ti/dma-crossbar.c @@ -3,14 +3,15 @@ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com * Author: Peter Ujfalusi */ +#include #include #include #include #include #include -#include -#include +#include #include +#include #define TI_XBAR_DRA7 0 #define TI_XBAR_AM335X 1 diff --git a/drivers/dma/ti/edma.c b/drivers/dma/ti/edma.c index 9ea91c640c324..aa8e2e8ac2609 100644 --- a/drivers/dma/ti/edma.c +++ b/drivers/dma/ti/edma.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include diff --git a/drivers/dma/ti/k3-udma-private.c b/drivers/dma/ti/k3-udma-private.c index 85e00701473cb..05228bf000333 100644 --- a/drivers/dma/ti/k3-udma-private.c +++ b/drivers/dma/ti/k3-udma-private.c @@ -3,6 +3,8 @@ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com * Author: Peter Ujfalusi */ +#include +#include int xudma_navss_psil_pair(struct udma_dev *ud, u32 src_thread, u32 dst_thread) { diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c index eb4dc5fffe646..30fd2f386f36a 100644 --- a/drivers/dma/ti/k3-udma.c +++ b/drivers/dma/ti/k3-udma.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c index 02e1c08c596d1..cf96cf915c0c7 100644 --- a/drivers/dma/ti/omap-dma.c +++ b/drivers/dma/ti/omap-dma.c @@ -16,8 +16,8 @@ #include #include #include +#include #include -#include #include "../virt-dma.h" diff --git a/drivers/dma/xgene-dma.c b/drivers/dma/xgene-dma.c index 3589b4ef50b83..bb4ff8c86733b 100644 --- a/drivers/dma/xgene-dma.c +++ b/drivers/dma/xgene-dma.c @@ -18,8 +18,9 @@ #include #include #include +#include #include -#include +#include #include "dmaengine.h" diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index ac09f0e5f58d8..8a4c98d28dfc4 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -41,10 +41,10 @@ #include #include #include -#include +#include #include -#include #include +#include #include #include #include diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c index 9360f43b8e0f3..bd8c3cc2eaab6 100644 --- a/drivers/dma/xilinx/zynqmp_dma.c +++ b/drivers/dma/xilinx/zynqmp_dma.c @@ -11,8 +11,9 @@ #include #include #include +#include #include -#include +#include #include #include #include -- GitLab From 926a4b17e9366583142c57e074d8a9e52cadc755 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 22 Jul 2023 17:58:40 +0200 Subject: [PATCH 0643/3445] dmaengine: ep93xx: Use struct_size() Use struct_size() instead of hand-writing it, when allocating a structure with a flex array. This is less verbose, more robust and more informative. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/36fa11d95b448b5f3f1677da41fe35b9e2751427.1690041500.git.christophe.jaillet@wanadoo.fr Signed-off-by: Vinod Koul --- drivers/dma/ep93xx_dma.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c index 5338a94f1a69f..5c4a448a12541 100644 --- a/drivers/dma/ep93xx_dma.c +++ b/drivers/dma/ep93xx_dma.c @@ -1320,11 +1320,9 @@ static int __init ep93xx_dma_probe(struct platform_device *pdev) struct ep93xx_dma_platform_data *pdata = dev_get_platdata(&pdev->dev); struct ep93xx_dma_engine *edma; struct dma_device *dma_dev; - size_t edma_size; int ret, i; - edma_size = pdata->num_channels * sizeof(struct ep93xx_dma_chan); - edma = kzalloc(sizeof(*edma) + edma_size, GFP_KERNEL); + edma = kzalloc(struct_size(edma, channels, pdata->num_channels), GFP_KERNEL); if (!edma) return -ENOMEM; -- GitLab From 0f264ab788ed9a39aabb36c0b35e5821b94bcdc8 Mon Sep 17 00:00:00 2001 From: Varshini Rajendran Date: Fri, 28 Jul 2023 15:54:51 +0530 Subject: [PATCH 0644/3445] dt-bindings: dmaengine: at_xdmac: add compatible with microchip,sam9x7 Add compatible for sam9x7. Signed-off-by: Varshini Rajendran Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230728102451.265869-1-varshini.rajendran@microchip.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/atmel-xdma.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/dma/atmel-xdma.txt b/Documentation/devicetree/bindings/dma/atmel-xdma.txt index 510b7f25ba242..76d649b3a25dc 100644 --- a/Documentation/devicetree/bindings/dma/atmel-xdma.txt +++ b/Documentation/devicetree/bindings/dma/atmel-xdma.txt @@ -3,7 +3,8 @@ * XDMA Controller Required properties: - compatible: Should be "atmel,sama5d4-dma", "microchip,sam9x60-dma" or - "microchip,sama7g5-dma". + "microchip,sama7g5-dma" or + "microchip,sam9x7-dma", "atmel,sama5d4-dma". - reg: Should contain DMA registers location and length. - interrupts: Should contain DMA interrupt. - #dma-cells: Must be <1>, used to represent the number of integer cells in -- GitLab From 54116d442e001e1b6bd482122043b1870998a1f3 Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Tue, 1 Aug 2023 16:44:52 -0700 Subject: [PATCH 0645/3445] Input: rpckbd - fix the return value handle for platform_get_irq() There is no possible for platform_get_irq() to return 0, and the return value of platform_get_irq() is more sensible to show the error reason. Signed-off-by: Ruan Jinjie Link: https://lore.kernel.org/r/20230731122246.2028651-1-ruanjinjie@huawei.com Signed-off-by: Dmitry Torokhov --- drivers/input/serio/rpckbd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c index ce420eb1f51be..e8a9709f32ebb 100644 --- a/drivers/input/serio/rpckbd.c +++ b/drivers/input/serio/rpckbd.c @@ -101,12 +101,12 @@ static int rpckbd_probe(struct platform_device *dev) int tx_irq, rx_irq; rx_irq = platform_get_irq(dev, 0); - if (rx_irq <= 0) - return rx_irq < 0 ? rx_irq : -ENXIO; + if (rx_irq < 0) + return rx_irq; tx_irq = platform_get_irq(dev, 1); - if (tx_irq <= 0) - return tx_irq < 0 ? tx_irq : -ENXIO; + if (tx_irq < 0) + return tx_irq; serio = kzalloc(sizeof(struct serio), GFP_KERNEL); rpckbd = kzalloc(sizeof(*rpckbd), GFP_KERNEL); -- GitLab From 61e6ae711ada4895d124082bc163586766579cd7 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Jul 2023 11:40:50 -0600 Subject: [PATCH 0646/3445] ata: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Signed-off-by: Damien Le Moal --- drivers/ata/ahci_ceva.c | 2 +- drivers/ata/ahci_dwc.c | 2 +- drivers/ata/ahci_mtk.c | 1 + drivers/ata/ahci_mvebu.c | 2 +- drivers/ata/ahci_qoriq.c | 2 -- drivers/ata/ahci_seattle.c | 1 - drivers/ata/ahci_sunxi.c | 2 +- drivers/ata/ahci_tegra.c | 2 +- drivers/ata/libahci_platform.c | 1 + drivers/ata/pata_ftide010.c | 3 +-- drivers/ata/pata_mpc52xx.c | 3 ++- drivers/ata/sata_dwc_460ex.c | 3 +-- drivers/ata/sata_fsl.c | 6 +++--- drivers/ata/sata_gemini.c | 3 +-- drivers/ata/sata_highbank.c | 2 +- drivers/ata/sata_rcar.c | 2 +- 16 files changed, 17 insertions(+), 20 deletions(-) diff --git a/drivers/ata/ahci_ceva.c b/drivers/ata/ahci_ceva.c index c2b6be083af43..64f7f7d6ba84e 100644 --- a/drivers/ata/ahci_ceva.c +++ b/drivers/ata/ahci_ceva.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include "ahci.h" diff --git a/drivers/ata/ahci_dwc.c b/drivers/ata/ahci_dwc.c index 9604a2f6ed489..ed263de3fd706 100644 --- a/drivers/ata/ahci_dwc.c +++ b/drivers/ata/ahci_dwc.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/ata/ahci_mtk.c b/drivers/ata/ahci_mtk.c index 5083fb6c49277..adc851cd55789 100644 --- a/drivers/ata/ahci_mtk.c +++ b/drivers/ata/ahci_mtk.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/ata/ahci_mvebu.c b/drivers/ata/ahci_mvebu.c index 7645015185823..f3187351e8a6c 100644 --- a/drivers/ata/ahci_mvebu.c +++ b/drivers/ata/ahci_mvebu.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include "ahci.h" diff --git a/drivers/ata/ahci_qoriq.c b/drivers/ata/ahci_qoriq.c index 3d01b118c9a1a..7bb9ad40605e6 100644 --- a/drivers/ata/ahci_qoriq.c +++ b/drivers/ata/ahci_qoriq.c @@ -12,9 +12,7 @@ #include #include #include -#include #include -#include #include #include #include "ahci.h" diff --git a/drivers/ata/ahci_seattle.c b/drivers/ata/ahci_seattle.c index 2c32d58c6ae75..adb33afee2b93 100644 --- a/drivers/ata/ahci_seattle.c +++ b/drivers/ata/ahci_seattle.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c index 04531fa95e404..58b2683954ddf 100644 --- a/drivers/ata/ahci_sunxi.c +++ b/drivers/ata/ahci_sunxi.c @@ -13,8 +13,8 @@ #include #include #include +#include #include -#include #include #include #include "ahci.h" diff --git a/drivers/ata/ahci_tegra.c b/drivers/ata/ahci_tegra.c index 21c20793e5177..223b60a7c8c79 100644 --- a/drivers/ata/ahci_tegra.c +++ b/drivers/ata/ahci_tegra.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index 9a8d43f54adcf..581704e61f286 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include "ahci.h" diff --git a/drivers/ata/pata_ftide010.c b/drivers/ata/pata_ftide010.c index 6f6734c09b111..9409fbd48c5a1 100644 --- a/drivers/ata/pata_ftide010.c +++ b/drivers/ata/pata_ftide010.c @@ -14,8 +14,7 @@ #include #include #include -#include -#include +#include #include #include "sata_gemini.h" diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index 66c9dea4ea6ee..56fad9a5bc653 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -19,9 +19,10 @@ #include #include #include +#include #include #include -#include +#include #include #include diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index fabdd1e380f94..d699c5f35153d 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -18,9 +18,8 @@ #include #include #include -#include +#include #include -#include #include #include #include diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index ccd99b9aa9ff7..16415eb093023 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -12,6 +12,9 @@ #include #include +#include +#include +#include #include #include @@ -19,9 +22,6 @@ #include #include #include -#include -#include -#include static unsigned int intr_coalescing_count; module_param(intr_coalescing_count, int, S_IRUGO); diff --git a/drivers/ata/sata_gemini.c b/drivers/ata/sata_gemini.c index c42cc9bbbc4ed..ca56d43df1493 100644 --- a/drivers/ata/sata_gemini.c +++ b/drivers/ata/sata_gemini.c @@ -12,8 +12,7 @@ #include #include #include -#include -#include +#include #include #include #include diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c index d6b324d03e597..7a6d41b7a02de 100644 --- a/drivers/ata/sata_highbank.c +++ b/drivers/ata/sata_highbank.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c index 34790f15c1b81..d4e40cf4c371e 100644 --- a/drivers/ata/sata_rcar.c +++ b/drivers/ata/sata_rcar.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include -- GitLab From 7addb10510525f2eda9db4473ab9bb1b881eb9f4 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 10:45:40 +0800 Subject: [PATCH 0647/3445] ata: ahci_octeon: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Signed-off-by: Damien Le Moal --- drivers/ata/ahci_octeon.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/ata/ahci_octeon.c b/drivers/ata/ahci_octeon.c index e89807fa928e4..9accf8923891a 100644 --- a/drivers/ata/ahci_octeon.c +++ b/drivers/ata/ahci_octeon.c @@ -31,13 +31,11 @@ static int ahci_octeon_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; - struct resource *res; void __iomem *base; u64 cfg; int ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); -- GitLab From 04fd6f563322c35632a38855eb5ec58bfdb41b36 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 10:45:41 +0800 Subject: [PATCH 0648/3445] ata: ahci_seattle: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Signed-off-by: Damien Le Moal --- drivers/ata/ahci_seattle.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/ata/ahci_seattle.c b/drivers/ata/ahci_seattle.c index adb33afee2b93..59f97aa7ac75c 100644 --- a/drivers/ata/ahci_seattle.c +++ b/drivers/ata/ahci_seattle.c @@ -131,8 +131,7 @@ static const struct ata_port_info *ahci_seattle_get_port_info( if (!plat_data) return &ahci_port_info; - plat_data->sgpio_ctrl = devm_ioremap_resource(dev, - platform_get_resource(pdev, IORESOURCE_MEM, 1)); + plat_data->sgpio_ctrl = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(plat_data->sgpio_ctrl)) return &ahci_port_info; -- GitLab From 6dd7830cf7650ca59834370ecd94cc7510ade527 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 10:45:42 +0800 Subject: [PATCH 0649/3445] ata: ahci_xgene: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Signed-off-by: Damien Le Moal --- drivers/ata/ahci_xgene.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index eb773f2e28fcb..f5deaf6486634 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -755,20 +755,17 @@ static int xgene_ahci_probe(struct platform_device *pdev) ctx->dev = dev; /* Retrieve the IP core resource */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - ctx->csr_core = devm_ioremap_resource(dev, res); + ctx->csr_core = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(ctx->csr_core)) return PTR_ERR(ctx->csr_core); /* Retrieve the IP diagnostic resource */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 2); - ctx->csr_diag = devm_ioremap_resource(dev, res); + ctx->csr_diag = devm_platform_ioremap_resource(pdev, 2); if (IS_ERR(ctx->csr_diag)) return PTR_ERR(ctx->csr_diag); /* Retrieve the IP AXI resource */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 3); - ctx->csr_axi = devm_ioremap_resource(dev, res); + ctx->csr_axi = devm_platform_ioremap_resource(pdev, 3); if (IS_ERR(ctx->csr_axi)) return PTR_ERR(ctx->csr_axi); -- GitLab From 7f187e74c7f95e3998de65813ac5f3ec0dca5e9a Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 10:45:43 +0800 Subject: [PATCH 0650/3445] ata: ahci_tegra: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Acked-by: Thierry Reding Signed-off-by: Damien Le Moal --- drivers/ata/ahci_tegra.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/ata/ahci_tegra.c b/drivers/ata/ahci_tegra.c index 223b60a7c8c79..8703c2a4658bb 100644 --- a/drivers/ata/ahci_tegra.c +++ b/drivers/ata/ahci_tegra.c @@ -530,8 +530,7 @@ static int tegra_ahci_probe(struct platform_device *pdev) tegra->pdev = pdev; tegra->soc = of_device_get_match_data(&pdev->dev); - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - tegra->sata_regs = devm_ioremap_resource(&pdev->dev, res); + tegra->sata_regs = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(tegra->sata_regs)) return PTR_ERR(tegra->sata_regs); -- GitLab From 827f6eaf39a152f562a41d828096723eaea7ec68 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 10:45:44 +0800 Subject: [PATCH 0651/3445] ata: sata_rcar: drop useless initializer There is no need to initialize the variable ret. Signed-off-by: Yangtao Li Reviewed-by: Sergey Shtylyov Reviewed-by: Geert Uytterhoeven Signed-off-by: Damien Le Moal --- drivers/ata/sata_rcar.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c index d4e40cf4c371e..9ac39bfac64bf 100644 --- a/drivers/ata/sata_rcar.c +++ b/drivers/ata/sata_rcar.c @@ -862,8 +862,7 @@ static int sata_rcar_probe(struct platform_device *pdev) struct ata_host *host; struct sata_rcar_priv *priv; struct resource *mem; - int irq; - int ret = 0; + int irq, ret; irq = platform_get_irq(pdev, 0); if (irq < 0) -- GitLab From 7763320fb96629022c014eb7a8ae72ef82bbe2b8 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 10:45:45 +0800 Subject: [PATCH 0652/3445] ata: sata_rcar: Remove unnecessary return value check As commit ce753ad1549c ("platform: finally disallow IRQ0 in platform_get_irq() and its ilk") says, there is no need to check if the platform_get_irq return value is 0. Let's remove it. Signed-off-by: Yangtao Li Reviewed-by: Sergey Shtylyov Reviewed-by: Geert Uytterhoeven Signed-off-by: Damien Le Moal --- drivers/ata/sata_rcar.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c index 9ac39bfac64bf..97f01e4e80543 100644 --- a/drivers/ata/sata_rcar.c +++ b/drivers/ata/sata_rcar.c @@ -867,8 +867,6 @@ static int sata_rcar_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; - if (!irq) - return -EINVAL; priv = devm_kzalloc(dev, sizeof(struct sata_rcar_priv), GFP_KERNEL); if (!priv) -- GitLab From 08c046e23595b284d91afb9a704148d25a27dad6 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 10:45:46 +0800 Subject: [PATCH 0653/3445] ata: sata_rcar: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Sergey Shtylyov Reviewed-by: Geert Uytterhoeven Signed-off-by: Damien Le Moal --- drivers/ata/sata_rcar.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c index 97f01e4e80543..16ce4af3b8942 100644 --- a/drivers/ata/sata_rcar.c +++ b/drivers/ata/sata_rcar.c @@ -861,7 +861,6 @@ static int sata_rcar_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct ata_host *host; struct sata_rcar_priv *priv; - struct resource *mem; int irq, ret; irq = platform_get_irq(pdev, 0); @@ -887,8 +886,7 @@ static int sata_rcar_probe(struct platform_device *pdev) host->private_data = priv; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->base = devm_ioremap_resource(dev, mem); + priv->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->base)) { ret = PTR_ERR(priv->base); goto err_pm_put; -- GitLab From b1aa998467c315228f3610da4fdfb455131692bb Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 10:45:47 +0800 Subject: [PATCH 0654/3445] ata: pata_ixp4xx: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Reviewed-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- drivers/ata/pata_ixp4xx_cf.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index b1daa4d3fcd97..1b9f67e16864d 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -242,12 +242,6 @@ static int ixp4xx_pata_probe(struct platform_device *pdev) int ret; int irq; - cmd = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ctl = platform_get_resource(pdev, IORESOURCE_MEM, 1); - - if (!cmd || !ctl) - return -EINVAL; - ixpp = devm_kzalloc(dev, sizeof(*ixpp), GFP_KERNEL); if (!ixpp) return -ENOMEM; @@ -271,10 +265,13 @@ static int ixp4xx_pata_probe(struct platform_device *pdev) if (ret) return ret; - ixpp->cmd = devm_ioremap_resource(dev, cmd); - ixpp->ctl = devm_ioremap_resource(dev, ctl); - if (IS_ERR(ixpp->cmd) || IS_ERR(ixpp->ctl)) - return -ENOMEM; + ixpp->cmd = devm_platform_get_and_ioremap_resource(pdev, 0, &cmd); + if (IS_ERR(ixpp->cmd)) + return PTR_ERR(ixpp->cmd); + + ixpp->ctl = devm_platform_get_and_ioremap_resource(pdev, 1, &ctl); + if (IS_ERR(ixpp->ctl)) + return PTR_ERR(ixpp->ctl); irq = platform_get_irq(pdev, 0); if (irq > 0) -- GitLab From 9402b802aa998d3f41efda331699d1621db957ec Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 10:45:48 +0800 Subject: [PATCH 0655/3445] ata: pata_ixp4xx: Remove unnecessary return value check As commit ce753ad1549c ("platform: finally disallow IRQ0 in platform_get_irq() and its ilk") says, there is no need to check if the platform_get_irq return value is 0. Let's remove it. Signed-off-by: Yangtao Li Reviewed-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- drivers/ata/pata_ixp4xx_cf.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 1b9f67e16864d..246bb4f8f1f7f 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -274,12 +274,9 @@ static int ixp4xx_pata_probe(struct platform_device *pdev) return PTR_ERR(ixpp->ctl); irq = platform_get_irq(pdev, 0); - if (irq > 0) - irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING); - else if (irq < 0) + if (irq < 0) return irq; - else - return -EINVAL; + irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING); /* Just one port to set up */ ixp4xx_setup_port(ixpp->host->ports[0], ixpp, cmd->start, ctl->start); -- GitLab From 2ade28916d20cc8fae0dd25da58a75ad62487424 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 10:45:49 +0800 Subject: [PATCH 0656/3445] ata: pata_ftide010: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Reviewed-by: Linus Walleij Reviewed-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- drivers/ata/pata_ftide010.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/ata/pata_ftide010.c b/drivers/ata/pata_ftide010.c index 9409fbd48c5a1..ae455f3de18e1 100644 --- a/drivers/ata/pata_ftide010.c +++ b/drivers/ata/pata_ftide010.c @@ -469,11 +469,7 @@ static int pata_ftide010_probe(struct platform_device *pdev) if (irq < 0) return irq; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - ftide->base = devm_ioremap_resource(dev, res); + ftide->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(ftide->base)) return PTR_ERR(ftide->base); -- GitLab From 282298e95b7623330c0ab08abd0a19e43f5d7472 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 10:45:50 +0800 Subject: [PATCH 0657/3445] ata: pata_imx: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Reviewed-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- drivers/ata/pata_imx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c index 4013f28679a9b..65d09ec94c121 100644 --- a/drivers/ata/pata_imx.c +++ b/drivers/ata/pata_imx.c @@ -164,8 +164,7 @@ static int pata_imx_probe(struct platform_device *pdev) ap->pio_mask = ATA_PIO4; ap->flags |= ATA_FLAG_SLAVE_POSS; - io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->host_regs = devm_ioremap_resource(&pdev->dev, io_res); + priv->host_regs = devm_platform_get_and_ioremap_resource(pdev, 0, &io_res); if (IS_ERR(priv->host_regs)) { ret = PTR_ERR(priv->host_regs); goto err; -- GitLab From 63b93099359eca37c11e4d5db5ea2c3a375f6026 Mon Sep 17 00:00:00 2001 From: Sergey Shtylyov Date: Sat, 29 Jul 2023 23:17:46 +0300 Subject: [PATCH 0658/3445] ata: libata: fix parameter type of ata_deadline() ata_deadline() passes its 'unsigned long timeout_msecs' parameter verbatim to msecs_to_jiffies() which takes just 'unsigned int' -- eliminate unneeded implicit cast... Signed-off-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- include/linux/libata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/libata.h b/include/linux/libata.h index 820f7a3a2749b..d9edb3d62a423 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1876,7 +1876,7 @@ static inline int ata_check_ready(u8 status) } static inline unsigned long ata_deadline(unsigned long from_jiffies, - unsigned long timeout_msecs) + unsigned int timeout_msecs) { return from_jiffies + msecs_to_jiffies(timeout_msecs); } -- GitLab From 84abed36d7de7145d393f9d5d05b36717e0cb49d Mon Sep 17 00:00:00 2001 From: Sergey Shtylyov Date: Sat, 29 Jul 2023 23:17:47 +0300 Subject: [PATCH 0659/3445] ata: libata-core: fix parameter types of ata_wait_register() ata_wait_register() passes its 'unsigned long {interval|timeout}' params verbatim to ata_{msleep|deadline}() that just take 'unsigned int' param for the time intervals in ms -- eliminate unneeded implicit casts... Signed-off-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- drivers/ata/libata-core.c | 2 +- include/linux/libata.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 04db0f2c683a7..54cc342c0b4f4 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6684,7 +6684,7 @@ EXPORT_SYMBOL_GPL(ata_msleep); * The final register value. */ u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask, u32 val, - unsigned long interval, unsigned long timeout) + unsigned int interval, unsigned int timeout) { unsigned long deadline; u32 tmp; diff --git a/include/linux/libata.h b/include/linux/libata.h index d9edb3d62a423..4772f64af734b 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1116,7 +1116,7 @@ static inline void ata_sas_port_resume(struct ata_port *ap) extern int ata_ratelimit(void); extern void ata_msleep(struct ata_port *ap, unsigned int msecs); extern u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask, - u32 val, unsigned long interval, unsigned long timeout); + u32 val, unsigned int interval, unsigned int timeout); extern int atapi_cmd_type(u8 opcode); extern unsigned int ata_pack_xfermask(unsigned int pio_mask, unsigned int mwdma_mask, -- GitLab From ca02f22516dd0f0a4842ec27916160b4b8fd3e5a Mon Sep 17 00:00:00 2001 From: Sergey Shtylyov Date: Sat, 29 Jul 2023 23:17:48 +0300 Subject: [PATCH 0660/3445] ata: libata-eh: fix reset timeout type ata_eh_reset_timeouts[] stores 'unsigned long' timeouts in ms, while ata_eh_reset() passes these values to ata_deadline() that takes just 'unsigned int timeout_msecs' parameter. Change the reset timeout table element's type to 'unsigned int' -- all timeouts fit into 'unsigned int' but we have to change ULONG_MAX to UINT_MAX... Signed-off-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- drivers/ata/libata-eh.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 35e03679b0bfe..0e2acca36c10d 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -78,12 +78,12 @@ enum { * are mostly for error handling, hotplug and those outlier devices that * take an exceptionally long time to recover from reset. */ -static const unsigned long ata_eh_reset_timeouts[] = { +static const unsigned int ata_eh_reset_timeouts[] = { 10000, /* most drives spin up by 10sec */ 10000, /* > 99% working drives spin up before 20sec */ 35000, /* give > 30 secs of idleness for outlier devices */ 5000, /* and sweet one last chance */ - ULONG_MAX, /* > 1 min has elapsed, give up */ + UINT_MAX, /* > 1 min has elapsed, give up */ }; static const unsigned int ata_eh_identify_timeouts[] = { @@ -2575,7 +2575,7 @@ int ata_eh_reset(struct ata_link *link, int classify, /* * Prepare to reset */ - while (ata_eh_reset_timeouts[max_tries] != ULONG_MAX) + while (ata_eh_reset_timeouts[max_tries] != UINT_MAX) max_tries++; if (link->flags & ATA_LFLAG_RST_ONCE) max_tries = 1; -- GitLab From d14d41cc5aaef138face9d5a145b460e2b63697a Mon Sep 17 00:00:00 2001 From: Sergey Shtylyov Date: Sat, 29 Jul 2023 23:17:49 +0300 Subject: [PATCH 0661/3445] ata: fix debounce timings type sata_deb_timing_{hotplug|long|normal}[] store 'unsigned long' debounce timeouts in ms, while sata_link_debounce() eventually uses those timeouts by calling ata_{deadline|msleep}( which take just 'unsigned int'. Change the debounce timeout table element's type to 'unsigned int' -- all these timeouts happily fit into 'unsigned int'... Signed-off-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- drivers/ata/ahci.c | 2 +- drivers/ata/ahci_qoriq.c | 2 +- drivers/ata/ahci_xgene.c | 2 +- drivers/ata/libahci.c | 2 +- drivers/ata/libata-core.c | 4 ++-- drivers/ata/libata-sata.c | 16 ++++++++-------- drivers/ata/libata-sff.c | 2 +- drivers/ata/sata_highbank.c | 2 +- drivers/ata/sata_inic162x.c | 2 +- drivers/ata/sata_mv.c | 2 +- drivers/ata/sata_nv.c | 2 +- include/linux/libata.h | 20 ++++++++++---------- 12 files changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index addba109406be..02503e903e4a8 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -807,7 +807,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { - const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + const unsigned int *timing = sata_ehc_deb_timing(&link->eh_context); struct ata_port *ap = link->ap; struct ahci_port_priv *pp = ap->private_data; struct ahci_host_priv *hpriv = ap->host->private_data; diff --git a/drivers/ata/ahci_qoriq.c b/drivers/ata/ahci_qoriq.c index 7bb9ad40605e6..b1a4e57578e20 100644 --- a/drivers/ata/ahci_qoriq.c +++ b/drivers/ata/ahci_qoriq.c @@ -88,7 +88,7 @@ MODULE_DEVICE_TABLE(acpi, ahci_qoriq_acpi_match); static int ahci_qoriq_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { - const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + const unsigned int *timing = sata_ehc_deb_timing(&link->eh_context); void __iomem *port_mmio = ahci_port_base(link->ap); u32 px_cmd, px_is, px_val; struct ata_port *ap = link->ap; diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index f5deaf6486634..8e88c86a2a78c 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -350,7 +350,7 @@ static void xgene_ahci_set_phy_cfg(struct xgene_ahci_context *ctx, int channel) static int xgene_ahci_do_hardreset(struct ata_link *link, unsigned long deadline, bool *online) { - const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + const unsigned int *timing = sata_ehc_deb_timing(&link->eh_context); struct ata_port *ap = link->ap; struct ahci_host_priv *hpriv = ap->host->private_data; struct xgene_ahci_context *ctx = hpriv->plat_data; diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 06aec35f88f2c..ad2bfcbff3bcb 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1587,7 +1587,7 @@ static int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class, int ahci_do_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline, bool *online) { - const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + const unsigned int *timing = sata_ehc_deb_timing(&link->eh_context); struct ata_port *ap = link->ap; struct ahci_port_priv *pp = ap->private_data; struct ahci_host_priv *hpriv = ap->host->private_data; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 54cc342c0b4f4..079ec8d0860f4 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3782,7 +3782,7 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline) { struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &link->eh_context; - const unsigned long *timing = sata_ehc_deb_timing(ehc); + const unsigned int *timing = sata_ehc_deb_timing(ehc); int rc; /* if we're about to do hardreset, nothing more to do */ @@ -3824,7 +3824,7 @@ EXPORT_SYMBOL_GPL(ata_std_prereset); int sata_std_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { - const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + const unsigned int *timing = sata_ehc_deb_timing(&link->eh_context); bool online; int rc; diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index 85e279a12f62c..5d393432fa065 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -19,11 +19,11 @@ #include "libata-transport.h" /* debounce timing parameters in msecs { interval, duration, timeout } */ -const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 }; +const unsigned int sata_deb_timing_normal[] = { 5, 100, 2000 }; EXPORT_SYMBOL_GPL(sata_deb_timing_normal); -const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 }; +const unsigned int sata_deb_timing_hotplug[] = { 25, 500, 2000 }; EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug); -const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 }; +const unsigned int sata_deb_timing_long[] = { 100, 2000, 5000 }; EXPORT_SYMBOL_GPL(sata_deb_timing_long); /** @@ -232,11 +232,11 @@ EXPORT_SYMBOL_GPL(ata_tf_from_fis); * RETURNS: * 0 on success, -errno on failure. */ -int sata_link_debounce(struct ata_link *link, const unsigned long *params, +int sata_link_debounce(struct ata_link *link, const unsigned int *params, unsigned long deadline) { - unsigned long interval = params[0]; - unsigned long duration = params[1]; + unsigned int interval = params[0]; + unsigned int duration = params[1]; unsigned long last_jiffies, t; u32 last, cur; int rc; @@ -295,7 +295,7 @@ EXPORT_SYMBOL_GPL(sata_link_debounce); * RETURNS: * 0 on success, -errno on failure. */ -int sata_link_resume(struct ata_link *link, const unsigned long *params, +int sata_link_resume(struct ata_link *link, const unsigned int *params, unsigned long deadline) { int tries = ATA_LINK_RESUME_TRIES; @@ -528,7 +528,7 @@ EXPORT_SYMBOL_GPL(sata_set_spd); * RETURNS: * 0 on success, -errno otherwise. */ -int sata_link_hardreset(struct ata_link *link, const unsigned long *timing, +int sata_link_hardreset(struct ata_link *link, const unsigned int *timing, unsigned long deadline, bool *online, int (*check_ready)(struct ata_link *)) { diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 9d28badfe41d6..ac55dfc2d85f7 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -1971,7 +1971,7 @@ int sata_sff_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { struct ata_eh_context *ehc = &link->eh_context; - const unsigned long *timing = sata_ehc_deb_timing(ehc); + const unsigned int *timing = sata_ehc_deb_timing(ehc); bool online; int rc; diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c index 7a6d41b7a02de..63ef7bb073ce0 100644 --- a/drivers/ata/sata_highbank.c +++ b/drivers/ata/sata_highbank.c @@ -385,7 +385,7 @@ static int highbank_initialize_phys(struct device *dev, void __iomem *addr) static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { - static const unsigned long timing[] = { 5, 100, 500}; + static const unsigned int timing[] = { 5, 100, 500}; struct ata_port *ap = link->ap; struct ahci_port_priv *pp = ap->private_data; struct ahci_host_priv *hpriv = ap->host->private_data; diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 2c8c78ed86c19..db9c255dc9f2e 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -619,7 +619,7 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class, struct ata_port *ap = link->ap; void __iomem *port_base = inic_port_base(ap); void __iomem *idma_ctl = port_base + PORT_IDMA_CTL; - const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + const unsigned int *timing = sata_ehc_deb_timing(&link->eh_context); int rc; /* hammer it into sane state */ diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index d404e631d1527..41c107e15c403 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -3633,7 +3633,7 @@ static int mv_hardreset(struct ata_link *link, unsigned int *class, /* Workaround for errata FEr SATA#10 (part 2) */ do { - const unsigned long *timing = + const unsigned int *timing = sata_ehc_deb_timing(&link->eh_context); rc = sata_link_hardreset(link, timing, deadline + extra, diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index abf5651c87ab4..0a0cee755bde7 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -1529,7 +1529,7 @@ static int nv_hardreset(struct ata_link *link, unsigned int *class, sata_link_hardreset(link, sata_deb_timing_hotplug, deadline, NULL, NULL); else { - const unsigned long *timing = sata_ehc_deb_timing(ehc); + const unsigned int *timing = sata_ehc_deb_timing(ehc); int rc; if (!(ehc->i.flags & ATA_EHI_QUIET)) diff --git a/include/linux/libata.h b/include/linux/libata.h index 4772f64af734b..8d510fb005913 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1166,11 +1166,11 @@ extern void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port * * SATA specific code - drivers/ata/libata-sata.c */ #ifdef CONFIG_SATA_HOST -extern const unsigned long sata_deb_timing_normal[]; -extern const unsigned long sata_deb_timing_hotplug[]; -extern const unsigned long sata_deb_timing_long[]; +extern const unsigned int sata_deb_timing_normal[]; +extern const unsigned int sata_deb_timing_hotplug[]; +extern const unsigned int sata_deb_timing_long[]; -static inline const unsigned long * +static inline const unsigned int * sata_ehc_deb_timing(struct ata_eh_context *ehc) { if (ehc->i.flags & ATA_EHI_HOTPLUGGED) @@ -1185,14 +1185,14 @@ extern int sata_scr_write(struct ata_link *link, int reg, u32 val); extern int sata_scr_write_flush(struct ata_link *link, int reg, u32 val); extern int sata_set_spd(struct ata_link *link); extern int sata_link_hardreset(struct ata_link *link, - const unsigned long *timing, unsigned long deadline, + const unsigned int *timing, unsigned long deadline, bool *online, int (*check_ready)(struct ata_link *)); -extern int sata_link_resume(struct ata_link *link, const unsigned long *params, +extern int sata_link_resume(struct ata_link *link, const unsigned int *params, unsigned long deadline); extern int ata_eh_read_sense_success_ncq_log(struct ata_link *link); extern void ata_eh_analyze_ncq_error(struct ata_link *link); #else -static inline const unsigned long * +static inline const unsigned int * sata_ehc_deb_timing(struct ata_eh_context *ehc) { return NULL; @@ -1212,7 +1212,7 @@ static inline int sata_scr_write_flush(struct ata_link *link, int reg, u32 val) } static inline int sata_set_spd(struct ata_link *link) { return -EOPNOTSUPP; } static inline int sata_link_hardreset(struct ata_link *link, - const unsigned long *timing, + const unsigned int *timing, unsigned long deadline, bool *online, int (*check_ready)(struct ata_link *)) @@ -1222,7 +1222,7 @@ static inline int sata_link_hardreset(struct ata_link *link, return -EOPNOTSUPP; } static inline int sata_link_resume(struct ata_link *link, - const unsigned long *params, + const unsigned int *params, unsigned long deadline) { return -EOPNOTSUPP; @@ -1234,7 +1234,7 @@ static inline int ata_eh_read_sense_success_ncq_log(struct ata_link *link) static inline void ata_eh_analyze_ncq_error(struct ata_link *link) { } #endif extern int sata_link_debounce(struct ata_link *link, - const unsigned long *params, unsigned long deadline); + const unsigned int *params, unsigned long deadline); extern int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy, bool spm_wakeup); extern int ata_slave_link_init(struct ata_port *ap); -- GitLab From 8c12536378085ed42e2f2b8223fcf82edda6c1c9 Mon Sep 17 00:00:00 2001 From: Sergey Shtylyov Date: Sat, 29 Jul 2023 23:17:50 +0300 Subject: [PATCH 0662/3445] ata: libata-scsi: fix timeout type in ata_scsi_park_store() ata_scsi_park_store() passes its 'long input' variable (if it's >= 0) to ata_deadline() that now takes 'unsigned int' -- eliminate unneeded implicit cast... Signed-off-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- drivers/ata/libata-scsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 370d18aca71e8..f39d603f05bc3 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -135,11 +135,11 @@ static ssize_t ata_scsi_park_store(struct device *device, struct scsi_device *sdev = to_scsi_device(device); struct ata_port *ap; struct ata_device *dev; - long int input; + int input; unsigned long flags; int rc; - rc = kstrtol(buf, 10, &input); + rc = kstrtoint(buf, 10, &input); if (rc) return rc; if (input < -2) -- GitLab From cc26436452de7599d1e561291dfeaae1004cc610 Mon Sep 17 00:00:00 2001 From: Sergey Shtylyov Date: Sat, 29 Jul 2023 23:17:51 +0300 Subject: [PATCH 0663/3445] ata: libahci: fix parameter type of ahci_exec_polled_cmd() ahci_exec_polled_cmd() passes its 'unsigned long timeout_msec' parameter to ata_wait_register() that now takes 'unsigned int' -- eliminate unneeded implicit casts, not forgetting about ahci_do_softreset()... Signed-off-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- drivers/ata/libahci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index ad2bfcbff3bcb..e2bacedf28ef5 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1403,7 +1403,7 @@ EXPORT_SYMBOL_GPL(ahci_kick_engine); static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, struct ata_taskfile *tf, int is_cmd, u16 flags, - unsigned long timeout_msec) + unsigned int timeout_msec) { const u32 cmd_fis_len = 5; /* five dwords */ struct ahci_port_priv *pp = ap->private_data; @@ -1448,7 +1448,8 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class, struct ahci_host_priv *hpriv = ap->host->private_data; struct ahci_port_priv *pp = ap->private_data; const char *reason = NULL; - unsigned long now, msecs; + unsigned long now; + unsigned int msecs; struct ata_taskfile tf; bool fbs_disabled = false; int rc; -- GitLab From 6da99acbffb41a17ee43d1920e8d82e5ab5a5fb8 Mon Sep 17 00:00:00 2001 From: Sergey Shtylyov Date: Sat, 29 Jul 2023 23:17:52 +0300 Subject: [PATCH 0664/3445] ata: ahci_xgene: fix parameter types of xgene_ahci_poll_reg_val() xgene_ahci_poll_reg_val() passes its 'unsigned long {interval|timeout}' params verbatim to ata_{msleep|deadline}() that just take 'unsigned int' param for the time intervals in ms -- eliminate unneeded implicit cast... Signed-off-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- drivers/ata/ahci_xgene.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index 8e88c86a2a78c..ccef5e63bdf9d 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -110,9 +110,8 @@ static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx) * @timeout : timeout for achieving the value. */ static int xgene_ahci_poll_reg_val(struct ata_port *ap, - void __iomem *reg, unsigned - int val, unsigned long interval, - unsigned long timeout) + void __iomem *reg, unsigned int val, + unsigned int interval, unsigned int timeout) { unsigned long deadline; unsigned int tmp; -- GitLab From 671b4493fc18e078022158adbc1f0c6c505b8fd0 Mon Sep 17 00:00:00 2001 From: Sergey Shtylyov Date: Sat, 29 Jul 2023 23:17:53 +0300 Subject: [PATCH 0665/3445] ata: sata_sil24: fix parameter type of sil24_exec_polled_cmd() sil24_exec_polled_cmd() passes its 'unsigned long timeout_msec' parameter to ata_wait_register() that now takes 'unsigned int' -- eliminate unneeded implicit casts, not forgetting about sil24_do_softreset()... Signed-off-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- drivers/ata/sata_sil24.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index e72a0257990d8..142e70bfc4982 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -597,7 +597,7 @@ static int sil24_init_port(struct ata_port *ap) static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp, const struct ata_taskfile *tf, int is_cmd, u32 ctrl, - unsigned long timeout_msec) + unsigned int timeout_msec) { void __iomem *port = sil24_port_base(ap); struct sil24_port_priv *pp = ap->private_data; @@ -651,7 +651,7 @@ static int sil24_softreset(struct ata_link *link, unsigned int *class, { struct ata_port *ap = link->ap; int pmp = sata_srst_pmp(link); - unsigned long timeout_msec = 0; + unsigned int timeout_msec = 0; struct ata_taskfile tf; const char *reason; int rc; -- GitLab From ff8072d589dcff7c1f0345a6ec98b5fc1e9ee2a1 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 31 Jul 2023 16:34:12 +0200 Subject: [PATCH 0666/3445] ata: libata: remove references to non-existing error_handler() With commit 65a15d6560df ("scsi: ipr: Remove SATA support") all libata drivers now have the error_handler() callback provided, so we can stop checking for non-existing error_handler callback. Signed-off-by: Hannes Reinecke [niklas: fixed review comments, rebased, solved conflicts during rebase, fixed bug that unconditionally dumped all QCs, removed the now unused function ata_dump_status(), removed the now unreachable failure paths in atapi_qc_complete(), removed the non-EH function to request ATAPI sense] Signed-off-by: Niklas Cassel Reviewed-by: John Garry Reviewed-by: Jason Yan Reviewed-by: Martin K. Petersen Signed-off-by: Damien Le Moal --- drivers/ata/libata-core.c | 209 +++++++++++++++----------------------- drivers/ata/libata-eh.c | 152 ++++++++++++--------------- drivers/ata/libata-sata.c | 7 +- drivers/ata/libata-scsi.c | 161 ++--------------------------- drivers/ata/libata-sff.c | 30 ++---- include/linux/libata.h | 2 +- 6 files changed, 170 insertions(+), 391 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 079ec8d0860f4..cc59d3158e1da 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1586,13 +1586,11 @@ static unsigned ata_exec_internal_sg(struct ata_device *dev, } } - if (ap->ops->error_handler) - ata_eh_release(ap); + ata_eh_release(ap); rc = wait_for_completion_timeout(&wait, msecs_to_jiffies(timeout)); - if (ap->ops->error_handler) - ata_eh_acquire(ap); + ata_eh_acquire(ap); ata_sff_flush_pio_task(ap); @@ -1607,10 +1605,7 @@ static unsigned ata_exec_internal_sg(struct ata_device *dev, if (qc->flags & ATA_QCFLAG_ACTIVE) { qc->err_mask |= AC_ERR_TIMEOUT; - if (ap->ops->error_handler) - ata_port_freeze(ap); - else - ata_qc_complete(qc); + ata_port_freeze(ap); ata_dev_warn(dev, "qc timeout after %u msecs (cmd 0x%x)\n", timeout, command); @@ -4874,126 +4869,103 @@ static void ata_verify_xfer(struct ata_queued_cmd *qc) void ata_qc_complete(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; + struct ata_device *dev = qc->dev; + struct ata_eh_info *ehi = &dev->link->eh_info; /* Trigger the LED (if available) */ ledtrig_disk_activity(!!(qc->tf.flags & ATA_TFLAG_WRITE)); - /* XXX: New EH and old EH use different mechanisms to - * synchronize EH with regular execution path. - * - * In new EH, a qc owned by EH is marked with ATA_QCFLAG_EH. - * Normal execution path is responsible for not accessing a - * qc owned by EH. libata core enforces the rule by returning NULL - * from ata_qc_from_tag() for qcs owned by EH. + /* + * In order to synchronize EH with the regular execution path, a qc that + * is owned by EH is marked with ATA_QCFLAG_EH. * - * Old EH depends on ata_qc_complete() nullifying completion - * requests if ATA_QCFLAG_EH_SCHEDULED is set. Old EH does - * not synchronize with interrupt handler. Only PIO task is - * taken care of. + * The normal execution path is responsible for not accessing a qc owned + * by EH. libata core enforces the rule by returning NULL from + * ata_qc_from_tag() for qcs owned by EH. */ - if (ap->ops->error_handler) { - struct ata_device *dev = qc->dev; - struct ata_eh_info *ehi = &dev->link->eh_info; - - if (unlikely(qc->err_mask)) - qc->flags |= ATA_QCFLAG_EH; + if (unlikely(qc->err_mask)) + qc->flags |= ATA_QCFLAG_EH; - /* - * Finish internal commands without any further processing - * and always with the result TF filled. - */ - if (unlikely(ata_tag_internal(qc->tag))) { - fill_result_tf(qc); - trace_ata_qc_complete_internal(qc); - __ata_qc_complete(qc); - return; - } + /* + * Finish internal commands without any further processing and always + * with the result TF filled. + */ + if (unlikely(ata_tag_internal(qc->tag))) { + fill_result_tf(qc); + trace_ata_qc_complete_internal(qc); + __ata_qc_complete(qc); + return; + } - /* - * Non-internal qc has failed. Fill the result TF and - * summon EH. - */ - if (unlikely(qc->flags & ATA_QCFLAG_EH)) { - fill_result_tf(qc); - trace_ata_qc_complete_failed(qc); - ata_qc_schedule_eh(qc); - return; - } + /* Non-internal qc has failed. Fill the result TF and summon EH. */ + if (unlikely(qc->flags & ATA_QCFLAG_EH)) { + fill_result_tf(qc); + trace_ata_qc_complete_failed(qc); + ata_qc_schedule_eh(qc); + return; + } - WARN_ON_ONCE(ata_port_is_frozen(ap)); + WARN_ON_ONCE(ata_port_is_frozen(ap)); - /* read result TF if requested */ - if (qc->flags & ATA_QCFLAG_RESULT_TF) - fill_result_tf(qc); + /* read result TF if requested */ + if (qc->flags & ATA_QCFLAG_RESULT_TF) + fill_result_tf(qc); - trace_ata_qc_complete_done(qc); + trace_ata_qc_complete_done(qc); + /* + * For CDL commands that completed without an error, check if we have + * sense data (ATA_SENSE is set). If we do, then the command may have + * been aborted by the device due to a limit timeout using the policy + * 0xD. For these commands, invoke EH to get the command sense data. + */ + if (qc->result_tf.status & ATA_SENSE && + ((ata_is_ncq(qc->tf.protocol) && + dev->flags & ATA_DFLAG_CDL_ENABLED) || + (!ata_is_ncq(qc->tf.protocol) && + ata_id_sense_reporting_enabled(dev->id)))) { /* - * For CDL commands that completed without an error, check if - * we have sense data (ATA_SENSE is set). If we do, then the - * command may have been aborted by the device due to a limit - * timeout using the policy 0xD. For these commands, invoke EH - * to get the command sense data. + * Tell SCSI EH to not overwrite scmd->result even if this + * command is finished with result SAM_STAT_GOOD. */ - if (qc->result_tf.status & ATA_SENSE && - ((ata_is_ncq(qc->tf.protocol) && - dev->flags & ATA_DFLAG_CDL_ENABLED) || - (!ata_is_ncq(qc->tf.protocol) && - ata_id_sense_reporting_enabled(dev->id)))) { - /* - * Tell SCSI EH to not overwrite scmd->result even if - * this command is finished with result SAM_STAT_GOOD. - */ - qc->scsicmd->flags |= SCMD_FORCE_EH_SUCCESS; - qc->flags |= ATA_QCFLAG_EH_SUCCESS_CMD; - ehi->dev_action[dev->devno] |= ATA_EH_GET_SUCCESS_SENSE; - - /* - * set pending so that ata_qc_schedule_eh() does not - * trigger fast drain, and freeze the port. - */ - ap->pflags |= ATA_PFLAG_EH_PENDING; - ata_qc_schedule_eh(qc); - return; - } + qc->scsicmd->flags |= SCMD_FORCE_EH_SUCCESS; + qc->flags |= ATA_QCFLAG_EH_SUCCESS_CMD; + ehi->dev_action[dev->devno] |= ATA_EH_GET_SUCCESS_SENSE; - /* Some commands need post-processing after successful - * completion. + /* + * set pending so that ata_qc_schedule_eh() does not trigger + * fast drain, and freeze the port. */ - switch (qc->tf.command) { - case ATA_CMD_SET_FEATURES: - if (qc->tf.feature != SETFEATURES_WC_ON && - qc->tf.feature != SETFEATURES_WC_OFF && - qc->tf.feature != SETFEATURES_RA_ON && - qc->tf.feature != SETFEATURES_RA_OFF) - break; - fallthrough; - case ATA_CMD_INIT_DEV_PARAMS: /* CHS translation changed */ - case ATA_CMD_SET_MULTI: /* multi_count changed */ - /* revalidate device */ - ehi->dev_action[dev->devno] |= ATA_EH_REVALIDATE; - ata_port_schedule_eh(ap); - break; + ap->pflags |= ATA_PFLAG_EH_PENDING; + ata_qc_schedule_eh(qc); + return; + } - case ATA_CMD_SLEEP: - dev->flags |= ATA_DFLAG_SLEEPING; + /* Some commands need post-processing after successful completion. */ + switch (qc->tf.command) { + case ATA_CMD_SET_FEATURES: + if (qc->tf.feature != SETFEATURES_WC_ON && + qc->tf.feature != SETFEATURES_WC_OFF && + qc->tf.feature != SETFEATURES_RA_ON && + qc->tf.feature != SETFEATURES_RA_OFF) break; - } - - if (unlikely(dev->flags & ATA_DFLAG_DUBIOUS_XFER)) - ata_verify_xfer(qc); + fallthrough; + case ATA_CMD_INIT_DEV_PARAMS: /* CHS translation changed */ + case ATA_CMD_SET_MULTI: /* multi_count changed */ + /* revalidate device */ + ehi->dev_action[dev->devno] |= ATA_EH_REVALIDATE; + ata_port_schedule_eh(ap); + break; - __ata_qc_complete(qc); - } else { - if (qc->flags & ATA_QCFLAG_EH_SCHEDULED) - return; + case ATA_CMD_SLEEP: + dev->flags |= ATA_DFLAG_SLEEPING; + break; + } - /* read result TF if failed or requested */ - if (qc->err_mask || qc->flags & ATA_QCFLAG_RESULT_TF) - fill_result_tf(qc); + if (unlikely(dev->flags & ATA_DFLAG_DUBIOUS_XFER)) + ata_verify_xfer(qc); - __ata_qc_complete(qc); - } + __ata_qc_complete(qc); } EXPORT_SYMBOL_GPL(ata_qc_complete); @@ -5039,11 +5011,8 @@ void ata_qc_issue(struct ata_queued_cmd *qc) struct ata_link *link = qc->dev->link; u8 prot = qc->tf.protocol; - /* Make sure only one non-NCQ command is outstanding. The - * check is skipped for old EH because it reuses active qc to - * request ATAPI sense. - */ - WARN_ON_ONCE(ap->ops->error_handler && ata_tag_valid(link->active_tag)); + /* Make sure only one non-NCQ command is outstanding. */ + WARN_ON_ONCE(ata_tag_valid(link->active_tag)); if (ata_is_ncq(prot)) { WARN_ON_ONCE(link->sactive & (1 << qc->hw_tag)); @@ -5917,15 +5886,9 @@ void __ata_port_probe(struct ata_port *ap) int ata_port_probe(struct ata_port *ap) { - int rc = 0; - - if (ap->ops->error_handler) { - __ata_port_probe(ap); - ata_port_wait_eh(ap); - } else { - rc = ata_bus_probe(ap); - } - return rc; + __ata_port_probe(ap); + ata_port_wait_eh(ap); + return 0; } @@ -6130,9 +6093,6 @@ static void ata_port_detach(struct ata_port *ap) struct ata_link *link; struct ata_device *dev; - if (!ap->ops->error_handler) - goto skip_eh; - /* tell EH we're leaving & flush EH */ spin_lock_irqsave(ap->lock, flags); ap->pflags |= ATA_PFLAG_UNLOADING; @@ -6148,7 +6108,6 @@ static void ata_port_detach(struct ata_port *ap) cancel_delayed_work_sync(&ap->hotplug_task); cancel_delayed_work_sync(&ap->scsi_rescan_task); - skip_eh: /* clean up zpodd on port removal */ ata_for_each_link(link, ap, HOST_FIRST) { ata_for_each_dev(dev, link, ALL) { diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 0e2acca36c10d..159ba6ba19ebb 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -571,13 +571,10 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, /* make sure sff pio task is not running */ ata_sff_flush_pio_task(ap); - if (!ap->ops->error_handler) - return; - /* synchronize with host lock and sort out timeouts */ /* - * For new EH, all qcs are finished in one of three ways - + * For EH, all qcs are finished in one of three ways - * normal completion, error completion, and SCSI timeout. * Both completions can race against SCSI timeout. When normal * completion wins, the qc never reaches EH. When error @@ -659,94 +656,87 @@ EXPORT_SYMBOL(ata_scsi_cmd_error_handler); void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap) { unsigned long flags; + struct ata_link *link; - /* invoke error handler */ - if (ap->ops->error_handler) { - struct ata_link *link; - - /* acquire EH ownership */ - ata_eh_acquire(ap); + /* acquire EH ownership */ + ata_eh_acquire(ap); repeat: - /* kill fast drain timer */ - del_timer_sync(&ap->fastdrain_timer); + /* kill fast drain timer */ + del_timer_sync(&ap->fastdrain_timer); - /* process port resume request */ - ata_eh_handle_port_resume(ap); + /* process port resume request */ + ata_eh_handle_port_resume(ap); - /* fetch & clear EH info */ - spin_lock_irqsave(ap->lock, flags); + /* fetch & clear EH info */ + spin_lock_irqsave(ap->lock, flags); - ata_for_each_link(link, ap, HOST_FIRST) { - struct ata_eh_context *ehc = &link->eh_context; - struct ata_device *dev; + ata_for_each_link(link, ap, HOST_FIRST) { + struct ata_eh_context *ehc = &link->eh_context; + struct ata_device *dev; - memset(&link->eh_context, 0, sizeof(link->eh_context)); - link->eh_context.i = link->eh_info; - memset(&link->eh_info, 0, sizeof(link->eh_info)); + memset(&link->eh_context, 0, sizeof(link->eh_context)); + link->eh_context.i = link->eh_info; + memset(&link->eh_info, 0, sizeof(link->eh_info)); - ata_for_each_dev(dev, link, ENABLED) { - int devno = dev->devno; + ata_for_each_dev(dev, link, ENABLED) { + int devno = dev->devno; - ehc->saved_xfer_mode[devno] = dev->xfer_mode; - if (ata_ncq_enabled(dev)) - ehc->saved_ncq_enabled |= 1 << devno; - } + ehc->saved_xfer_mode[devno] = dev->xfer_mode; + if (ata_ncq_enabled(dev)) + ehc->saved_ncq_enabled |= 1 << devno; } + } - ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS; - ap->pflags &= ~ATA_PFLAG_EH_PENDING; - ap->excl_link = NULL; /* don't maintain exclusion over EH */ + ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS; + ap->pflags &= ~ATA_PFLAG_EH_PENDING; + ap->excl_link = NULL; /* don't maintain exclusion over EH */ - spin_unlock_irqrestore(ap->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); - /* invoke EH, skip if unloading or suspended */ - if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED))) - ap->ops->error_handler(ap); - else { - /* if unloading, commence suicide */ - if ((ap->pflags & ATA_PFLAG_UNLOADING) && - !(ap->pflags & ATA_PFLAG_UNLOADED)) - ata_eh_unload(ap); - ata_eh_finish(ap); - } + /* invoke EH, skip if unloading or suspended */ + if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED))) + ap->ops->error_handler(ap); + else { + /* if unloading, commence suicide */ + if ((ap->pflags & ATA_PFLAG_UNLOADING) && + !(ap->pflags & ATA_PFLAG_UNLOADED)) + ata_eh_unload(ap); + ata_eh_finish(ap); + } - /* process port suspend request */ - ata_eh_handle_port_suspend(ap); + /* process port suspend request */ + ata_eh_handle_port_suspend(ap); - /* Exception might have happened after ->error_handler - * recovered the port but before this point. Repeat - * EH in such case. - */ - spin_lock_irqsave(ap->lock, flags); + /* + * Exception might have happened after ->error_handler recovered the + * port but before this point. Repeat EH in such case. + */ + spin_lock_irqsave(ap->lock, flags); - if (ap->pflags & ATA_PFLAG_EH_PENDING) { - if (--ap->eh_tries) { - spin_unlock_irqrestore(ap->lock, flags); - goto repeat; - } - ata_port_err(ap, - "EH pending after %d tries, giving up\n", - ATA_EH_MAX_TRIES); - ap->pflags &= ~ATA_PFLAG_EH_PENDING; + if (ap->pflags & ATA_PFLAG_EH_PENDING) { + if (--ap->eh_tries) { + spin_unlock_irqrestore(ap->lock, flags); + goto repeat; } + ata_port_err(ap, + "EH pending after %d tries, giving up\n", + ATA_EH_MAX_TRIES); + ap->pflags &= ~ATA_PFLAG_EH_PENDING; + } - /* this run is complete, make sure EH info is clear */ - ata_for_each_link(link, ap, HOST_FIRST) - memset(&link->eh_info, 0, sizeof(link->eh_info)); + /* this run is complete, make sure EH info is clear */ + ata_for_each_link(link, ap, HOST_FIRST) + memset(&link->eh_info, 0, sizeof(link->eh_info)); - /* end eh (clear host_eh_scheduled) while holding - * ap->lock such that if exception occurs after this - * point but before EH completion, SCSI midlayer will - * re-initiate EH. - */ - ap->ops->end_eh(ap); + /* + * end eh (clear host_eh_scheduled) while holding ap->lock such that if + * exception occurs after this point but before EH completion, SCSI + * midlayer will re-initiate EH. + */ + ap->ops->end_eh(ap); - spin_unlock_irqrestore(ap->lock, flags); - ata_eh_release(ap); - } else { - WARN_ON(ata_qc_from_tag(ap, ap->link.active_tag) == NULL); - ap->ops->eng_timeout(ap); - } + spin_unlock_irqrestore(ap->lock, flags); + ata_eh_release(ap); scsi_eh_flush_done_q(&ap->eh_done_q); @@ -912,8 +902,6 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - WARN_ON(!ap->ops->error_handler); - qc->flags |= ATA_QCFLAG_EH; ata_eh_set_pending(ap, 1); @@ -934,8 +922,6 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc) */ void ata_std_sched_eh(struct ata_port *ap) { - WARN_ON(!ap->ops->error_handler); - if (ap->pflags & ATA_PFLAG_INITIALIZING) return; @@ -989,8 +975,6 @@ static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link) struct ata_queued_cmd *qc; int tag, nr_aborted = 0; - WARN_ON(!ap->ops->error_handler); - /* we're gonna abort all commands, no need for fast drain */ ata_eh_set_pending(ap, 0); @@ -1065,8 +1049,6 @@ EXPORT_SYMBOL_GPL(ata_port_abort); */ static void __ata_port_freeze(struct ata_port *ap) { - WARN_ON(!ap->ops->error_handler); - if (ap->ops->freeze) ap->ops->freeze(ap); @@ -1091,8 +1073,6 @@ static void __ata_port_freeze(struct ata_port *ap) */ int ata_port_freeze(struct ata_port *ap) { - WARN_ON(!ap->ops->error_handler); - __ata_port_freeze(ap); return ata_port_abort(ap); @@ -1112,9 +1092,6 @@ void ata_eh_freeze_port(struct ata_port *ap) { unsigned long flags; - if (!ap->ops->error_handler) - return; - spin_lock_irqsave(ap->lock, flags); __ata_port_freeze(ap); spin_unlock_irqrestore(ap->lock, flags); @@ -1134,9 +1111,6 @@ void ata_eh_thaw_port(struct ata_port *ap) { unsigned long flags; - if (!ap->ops->error_handler) - return; - spin_lock_irqsave(ap->lock, flags); ap->pflags &= ~ATA_PFLAG_FROZEN; diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index 5d393432fa065..cf401a54c9e16 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -1158,12 +1158,7 @@ EXPORT_SYMBOL_GPL(ata_sas_port_alloc); */ int ata_sas_port_start(struct ata_port *ap) { - /* - * the port is marked as frozen at allocation time, but if we don't - * have new eh, we won't thaw it - */ - if (!ap->ops->error_handler) - ap->pflags &= ~ATA_PFLAG_FROZEN; + /* the port is marked as frozen at allocation time */ return 0; } EXPORT_SYMBOL_GPL(ata_sas_port_start); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index f39d603f05bc3..c3f745a4e5eac 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -709,47 +709,6 @@ static void ata_qc_set_pc_nbytes(struct ata_queued_cmd *qc) qc->nbytes = scsi_bufflen(scmd) + qc->extrabytes; } -/** - * ata_dump_status - user friendly display of error info - * @ap: the port in question - * @tf: ptr to filled out taskfile - * - * Decode and dump the ATA error/status registers for the user so - * that they have some idea what really happened at the non - * make-believe layer. - * - * LOCKING: - * inherited from caller - */ -static void ata_dump_status(struct ata_port *ap, struct ata_taskfile *tf) -{ - u8 stat = tf->status, err = tf->error; - - if (stat & ATA_BUSY) { - ata_port_warn(ap, "status=0x%02x {Busy} ", stat); - } else { - ata_port_warn(ap, "status=0x%02x { %s%s%s%s%s%s%s} ", stat, - stat & ATA_DRDY ? "DriveReady " : "", - stat & ATA_DF ? "DeviceFault " : "", - stat & ATA_DSC ? "SeekComplete " : "", - stat & ATA_DRQ ? "DataRequest " : "", - stat & ATA_CORR ? "CorrectedError " : "", - stat & ATA_SENSE ? "Sense " : "", - stat & ATA_ERR ? "Error " : ""); - if (err) - ata_port_warn(ap, "error=0x%02x {%s%s%s%s%s%s", err, - err & ATA_ABORTED ? - "DriveStatusError " : "", - err & ATA_ICRC ? - (err & ATA_ABORTED ? - "BadCRC " : "Sector ") : "", - err & ATA_UNC ? "UncorrectableError " : "", - err & ATA_IDNF ? "SectorIdNotFound " : "", - err & ATA_TRK0NF ? "TrackZeroNotFound " : "", - err & ATA_AMNF ? "AddrMarkNotFound " : ""); - } -} - /** * ata_to_sense_error - convert ATA error to SCSI error * @id: ATA device number @@ -758,7 +717,6 @@ static void ata_dump_status(struct ata_port *ap, struct ata_taskfile *tf) * @sk: the sense key we'll fill out * @asc: the additional sense code we'll fill out * @ascq: the additional sense code qualifier we'll fill out - * @verbose: be verbose * * Converts an ATA error into a SCSI error. Fill out pointers to * SK, ASC, and ASCQ bytes for later use in fixed or descriptor @@ -768,7 +726,7 @@ static void ata_dump_status(struct ata_port *ap, struct ata_taskfile *tf) * spin_lock_irqsave(host lock) */ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, - u8 *asc, u8 *ascq, int verbose) + u8 *asc, u8 *ascq) { int i; @@ -847,7 +805,7 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, *sk = sense_table[i][1]; *asc = sense_table[i][2]; *ascq = sense_table[i][3]; - goto translate_done; + return; } } } @@ -862,7 +820,7 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, *sk = stat_table[i][1]; *asc = stat_table[i][2]; *ascq = stat_table[i][3]; - goto translate_done; + return; } } @@ -873,12 +831,6 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, *sk = ABORTED_COMMAND; *asc = 0x00; *ascq = 0x00; - - translate_done: - if (verbose) - pr_err("ata%u: translated ATA stat/err 0x%02x/%02x to SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n", - id, drv_stat, drv_err, *sk, *asc, *ascq); - return; } /* @@ -904,7 +856,6 @@ static void ata_gen_passthru_sense(struct ata_queued_cmd *qc) struct ata_taskfile *tf = &qc->result_tf; unsigned char *sb = cmd->sense_buffer; unsigned char *desc = sb + 8; - int verbose = qc->ap->ops->error_handler == NULL; u8 sense_key, asc, ascq; memset(sb, 0, SCSI_SENSE_BUFFERSIZE); @@ -916,7 +867,7 @@ static void ata_gen_passthru_sense(struct ata_queued_cmd *qc) if (qc->err_mask || tf->status & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) { ata_to_sense_error(qc->ap->print_id, tf->status, tf->error, - &sense_key, &asc, &ascq, verbose); + &sense_key, &asc, &ascq); ata_scsi_set_sense(qc->dev, cmd, sense_key, asc, ascq); } else { /* @@ -999,7 +950,6 @@ static void ata_gen_ata_sense(struct ata_queued_cmd *qc) struct scsi_cmnd *cmd = qc->scsicmd; struct ata_taskfile *tf = &qc->result_tf; unsigned char *sb = cmd->sense_buffer; - int verbose = qc->ap->ops->error_handler == NULL; u64 block; u8 sense_key, asc, ascq; @@ -1017,7 +967,7 @@ static void ata_gen_ata_sense(struct ata_queued_cmd *qc) if (qc->err_mask || tf->status & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) { ata_to_sense_error(qc->ap->print_id, tf->status, tf->error, - &sense_key, &asc, &ascq, verbose); + &sense_key, &asc, &ascq); ata_scsi_set_sense(dev, cmd, sense_key, asc, ascq); } else { /* Could not decode error */ @@ -1179,9 +1129,6 @@ void ata_scsi_slave_destroy(struct scsi_device *sdev) unsigned long flags; struct ata_device *dev; - if (!ap->ops->error_handler) - return; - spin_lock_irqsave(ap->lock, flags); dev = __ata_scsi_find_dev(ap, sdev); if (dev && dev->sdev) { @@ -1668,7 +1615,6 @@ static void ata_qc_done(struct ata_queued_cmd *qc) static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) { - struct ata_port *ap = qc->ap; struct scsi_cmnd *cmd = qc->scsicmd; u8 *cdb = cmd->cmnd; int need_sense = (qc->err_mask != 0) && @@ -1692,9 +1638,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) /* Keep the SCSI ML and status byte, clear host byte. */ cmd->result &= 0x0000ffff; - if (need_sense && !ap->ops->error_handler) - ata_dump_status(ap, &qc->result_tf); - ata_qc_done(qc); } @@ -2601,71 +2544,6 @@ static unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf) return 0; } -static void atapi_sense_complete(struct ata_queued_cmd *qc) -{ - if (qc->err_mask && ((qc->err_mask & AC_ERR_DEV) == 0)) { - /* FIXME: not quite right; we don't want the - * translation of taskfile registers into - * a sense descriptors, since that's only - * correct for ATA, not ATAPI - */ - ata_gen_passthru_sense(qc); - } - - ata_qc_done(qc); -} - -/* is it pointless to prefer PIO for "safety reasons"? */ -static inline int ata_pio_use_silly(struct ata_port *ap) -{ - return (ap->flags & ATA_FLAG_PIO_DMA); -} - -static void atapi_request_sense(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct scsi_cmnd *cmd = qc->scsicmd; - - memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); - -#ifdef CONFIG_ATA_SFF - if (ap->ops->sff_tf_read) - ap->ops->sff_tf_read(ap, &qc->tf); -#endif - - /* fill these in, for the case where they are -not- overwritten */ - cmd->sense_buffer[0] = 0x70; - cmd->sense_buffer[2] = qc->tf.error >> 4; - - ata_qc_reinit(qc); - - /* setup sg table and init transfer direction */ - sg_init_one(&qc->sgent, cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE); - ata_sg_init(qc, &qc->sgent, 1); - qc->dma_dir = DMA_FROM_DEVICE; - - memset(&qc->cdb, 0, qc->dev->cdb_len); - qc->cdb[0] = REQUEST_SENSE; - qc->cdb[4] = SCSI_SENSE_BUFFERSIZE; - - qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - qc->tf.command = ATA_CMD_PACKET; - - if (ata_pio_use_silly(ap)) { - qc->tf.protocol = ATAPI_PROT_DMA; - qc->tf.feature |= ATAPI_PKT_DMA; - } else { - qc->tf.protocol = ATAPI_PROT_PIO; - qc->tf.lbam = SCSI_SENSE_BUFFERSIZE; - qc->tf.lbah = 0; - } - qc->nbytes = SCSI_SENSE_BUFFERSIZE; - - qc->complete_fn = atapi_sense_complete; - - ata_qc_issue(qc); -} - /* * ATAPI devices typically report zero for their SCSI version, and sometimes * deviate from the spec WRT response data format. If SCSI version is @@ -2691,9 +2569,8 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) struct scsi_cmnd *cmd = qc->scsicmd; unsigned int err_mask = qc->err_mask; - /* handle completion from new EH */ - if (unlikely(qc->ap->ops->error_handler && - (err_mask || qc->flags & ATA_QCFLAG_SENSE_VALID))) { + /* handle completion from EH */ + if (unlikely(err_mask || qc->flags & ATA_QCFLAG_SENSE_VALID)) { if (!(qc->flags & ATA_QCFLAG_SENSE_VALID)) { /* FIXME: not quite right; we don't want the @@ -2725,23 +2602,10 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) return; } - /* successful completion or old EH failure path */ - if (unlikely(err_mask & AC_ERR_DEV)) { - cmd->result = SAM_STAT_CHECK_CONDITION; - atapi_request_sense(qc); - return; - } else if (unlikely(err_mask)) { - /* FIXME: not quite right; we don't want the - * translation of taskfile registers into - * a sense descriptors, since that's only - * correct for ATA, not ATAPI - */ - ata_gen_passthru_sense(qc); - } else { - if (cmd->cmnd[0] == INQUIRY && (cmd->cmnd[1] & 0x03) == 0) - atapi_fixup_inquiry(cmd); - cmd->result = SAM_STAT_GOOD; - } + /* successful completion path */ + if (cmd->cmnd[0] == INQUIRY && (cmd->cmnd[1] & 0x03) == 0) + atapi_fixup_inquiry(cmd); + cmd->result = SAM_STAT_GOOD; ata_qc_done(qc); } @@ -4790,9 +4654,6 @@ int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, unsigned long flags; int devno, rc = 0; - if (!ap->ops->error_handler) - return -EOPNOTSUPP; - if (lun != SCAN_WILD_CARD && lun) return -EINVAL; diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index ac55dfc2d85f7..8fcc622fcb3d4 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -883,31 +883,21 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) { struct ata_port *ap = qc->ap; - if (ap->ops->error_handler) { - if (in_wq) { - /* EH might have kicked in while host lock is - * released. - */ - qc = ata_qc_from_tag(ap, qc->tag); - if (qc) { - if (likely(!(qc->err_mask & AC_ERR_HSM))) { - ata_sff_irq_on(ap); - ata_qc_complete(qc); - } else - ata_port_freeze(ap); - } - } else { - if (likely(!(qc->err_mask & AC_ERR_HSM))) + if (in_wq) { + /* EH might have kicked in while host lock is released. */ + qc = ata_qc_from_tag(ap, qc->tag); + if (qc) { + if (likely(!(qc->err_mask & AC_ERR_HSM))) { + ata_sff_irq_on(ap); ata_qc_complete(qc); - else + } else ata_port_freeze(ap); } } else { - if (in_wq) { - ata_sff_irq_on(ap); - ata_qc_complete(qc); - } else + if (likely(!(qc->err_mask & AC_ERR_HSM))) ata_qc_complete(qc); + else + ata_port_freeze(ap); } } diff --git a/include/linux/libata.h b/include/linux/libata.h index 8d510fb005913..d61e5465076e9 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1785,7 +1785,7 @@ static inline struct ata_queued_cmd *ata_qc_from_tag(struct ata_port *ap, { struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); - if (unlikely(!qc) || !ap->ops->error_handler) + if (unlikely(!qc)) return qc; if ((qc->flags & (ATA_QCFLAG_ACTIVE | -- GitLab From 43aa43351bb551a7732c1b9f6e8ebb9a6f30b063 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 31 Jul 2023 16:34:13 +0200 Subject: [PATCH 0667/3445] ata,scsi: remove ata_sas_port_{start,stop} callbacks Callbacks are empty now, so remove them. Also, remove the call to ap->ops->port_start() in ata_sas_port_init(), as this would otherwise cause a NULL pointer dereference, now when the callback is gone. Signed-off-by: Hannes Reinecke [niklas: remove the call to ap->ops->port_start() in ata_sas_port_init()] Signed-off-by: Niklas Cassel Reviewed-by: Jason Yan Reviewed-by: John Garry Reviewed-by: Martin K. Petersen Signed-off-by: Damien Le Moal --- drivers/ata/libata-sata.c | 38 ----------------------------------- drivers/scsi/libsas/sas_ata.c | 2 -- include/linux/libata.h | 2 -- 3 files changed, 42 deletions(-) diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index cf401a54c9e16..ce392b5b5930f 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -1144,40 +1144,6 @@ struct ata_port *ata_sas_port_alloc(struct ata_host *host, } EXPORT_SYMBOL_GPL(ata_sas_port_alloc); -/** - * ata_sas_port_start - Set port up for dma. - * @ap: Port to initialize - * - * Called just after data structures for each port are - * initialized. - * - * May be used as the port_start() entry in ata_port_operations. - * - * LOCKING: - * Inherited from caller. - */ -int ata_sas_port_start(struct ata_port *ap) -{ - /* the port is marked as frozen at allocation time */ - return 0; -} -EXPORT_SYMBOL_GPL(ata_sas_port_start); - -/** - * ata_sas_port_stop - Undo ata_sas_port_start() - * @ap: Port to shut down - * - * May be used as the port_stop() entry in ata_port_operations. - * - * LOCKING: - * Inherited from caller. - */ - -void ata_sas_port_stop(struct ata_port *ap) -{ -} -EXPORT_SYMBOL_GPL(ata_sas_port_stop); - /** * ata_sas_async_probe - simply schedule probing and return * @ap: Port to probe @@ -1211,10 +1177,6 @@ EXPORT_SYMBOL_GPL(ata_sas_sync_probe); int ata_sas_port_init(struct ata_port *ap) { - int rc = ap->ops->port_start(ap); - - if (rc) - return rc; ap->print_id = atomic_inc_return(&ata_print_id); return 0; } diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 77714a495cbba..7ead1f1be97fb 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -565,8 +565,6 @@ static struct ata_port_operations sas_sata_ops = { .qc_prep = ata_noop_qc_prep, .qc_issue = sas_ata_qc_issue, .qc_fill_rtf = sas_ata_qc_fill_rtf, - .port_start = ata_sas_port_start, - .port_stop = ata_sas_port_stop, .set_dmamode = sas_ata_set_dmamode, .sched_eh = sas_ata_sched_eh, .end_eh = sas_ata_end_eh, diff --git a/include/linux/libata.h b/include/linux/libata.h index d61e5465076e9..f8f8b558a8be2 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1244,10 +1244,8 @@ extern struct ata_port *ata_sas_port_alloc(struct ata_host *, extern void ata_sas_async_probe(struct ata_port *ap); extern int ata_sas_sync_probe(struct ata_port *ap); extern int ata_sas_port_init(struct ata_port *); -extern int ata_sas_port_start(struct ata_port *ap); extern int ata_sas_tport_add(struct device *parent, struct ata_port *ap); extern void ata_sas_tport_delete(struct ata_port *ap); -extern void ata_sas_port_stop(struct ata_port *ap); extern int ata_sas_slave_configure(struct scsi_device *, struct ata_port *); extern int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap); extern void ata_tf_to_fis(const struct ata_taskfile *tf, -- GitLab From 6c2fe21e08c28bbdb53ada668edea7df1aa9fb1e Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 31 Jul 2023 16:34:14 +0200 Subject: [PATCH 0668/3445] ata,scsi: remove ata_sas_port_destroy() Is now a wrapper around kfree(), so call it directly. Signed-off-by: Hannes Reinecke Signed-off-by: Niklas Cassel Reviewed-by: John Garry Reviewed-by: Jason Yan Reviewed-by: Martin K. Petersen Signed-off-by: Damien Le Moal --- drivers/ata/libata-sata.c | 14 -------------- drivers/scsi/libsas/sas_ata.c | 2 +- drivers/scsi/libsas/sas_discover.c | 2 +- include/linux/libata.h | 1 - 4 files changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index ce392b5b5930f..c149a46fadaf7 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -1194,20 +1194,6 @@ void ata_sas_tport_delete(struct ata_port *ap) } EXPORT_SYMBOL_GPL(ata_sas_tport_delete); -/** - * ata_sas_port_destroy - Destroy a SATA port allocated by ata_sas_port_alloc - * @ap: SATA port to destroy - * - */ - -void ata_sas_port_destroy(struct ata_port *ap) -{ - if (ap->ops->port_stop) - ap->ops->port_stop(ap); - kfree(ap); -} -EXPORT_SYMBOL_GPL(ata_sas_port_destroy); - /** * ata_sas_slave_configure - Default slave_config routine for libata devices * @sdev: SCSI device to configure diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 7ead1f1be97fb..a2eb9a2191c0f 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -619,7 +619,7 @@ int sas_ata_init(struct domain_device *found_dev) return 0; destroy_port: - ata_sas_port_destroy(ap); + kfree(ap); free_host: ata_host_put(ata_host); return rc; diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 8c6afe724944b..07e18cdb85c72 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -301,7 +301,7 @@ void sas_free_device(struct kref *kref) if (dev_is_sata(dev) && dev->sata_dev.ap) { ata_sas_tport_delete(dev->sata_dev.ap); - ata_sas_port_destroy(dev->sata_dev.ap); + kfree(dev->sata_dev.ap); ata_host_put(dev->sata_dev.ata_host); dev->sata_dev.ata_host = NULL; dev->sata_dev.ap = NULL; diff --git a/include/linux/libata.h b/include/linux/libata.h index f8f8b558a8be2..1d1fd16a1492a 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1238,7 +1238,6 @@ extern int sata_link_debounce(struct ata_link *link, extern int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy, bool spm_wakeup); extern int ata_slave_link_init(struct ata_port *ap); -extern void ata_sas_port_destroy(struct ata_port *); extern struct ata_port *ata_sas_port_alloc(struct ata_host *, struct ata_port_info *, struct Scsi_Host *); extern void ata_sas_async_probe(struct ata_port *ap); -- GitLab From 8ac161ea2b3709b789c192de7da31a58aec9d7ee Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 31 Jul 2023 16:34:15 +0200 Subject: [PATCH 0669/3445] ata: libata-sata: remove ata_sas_sync_probe() Unused. Signed-off-by: Hannes Reinecke Signed-off-by: Niklas Cassel Reviewed-by: Jason Yan Reviewed-by: John Garry Reviewed-by: Martin K. Petersen Signed-off-by: Damien Le Moal --- drivers/ata/libata-sata.c | 7 ------- include/linux/libata.h | 1 - 2 files changed, 8 deletions(-) diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index c149a46fadaf7..04ab2bedcaa24 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -1157,13 +1157,6 @@ void ata_sas_async_probe(struct ata_port *ap) } EXPORT_SYMBOL_GPL(ata_sas_async_probe); -int ata_sas_sync_probe(struct ata_port *ap) -{ - return ata_port_probe(ap); -} -EXPORT_SYMBOL_GPL(ata_sas_sync_probe); - - /** * ata_sas_port_init - Initialize a SATA device * @ap: SATA port to initialize diff --git a/include/linux/libata.h b/include/linux/libata.h index 1d1fd16a1492a..d08dde8c8ad2d 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1241,7 +1241,6 @@ extern int ata_slave_link_init(struct ata_port *ap); extern struct ata_port *ata_sas_port_alloc(struct ata_host *, struct ata_port_info *, struct Scsi_Host *); extern void ata_sas_async_probe(struct ata_port *ap); -extern int ata_sas_sync_probe(struct ata_port *ap); extern int ata_sas_port_init(struct ata_port *); extern int ata_sas_tport_add(struct device *parent, struct ata_port *ap); extern void ata_sas_tport_delete(struct ata_port *ap); -- GitLab From 77461a3ff72f3ad9fd0b8765548c7e2fbaf52ede Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 31 Jul 2023 16:34:16 +0200 Subject: [PATCH 0670/3445] ata: libata-core: inline ata_port_probe() Just used in one place. Signed-off-by: Hannes Reinecke Signed-off-by: Niklas Cassel Reviewed-by: Jason Yan Reviewed-by: John Garry Reviewed-by: Martin K. Petersen Signed-off-by: Damien Le Moal --- drivers/ata/libata-core.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index cc59d3158e1da..c6e624d27f46d 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5884,14 +5884,6 @@ void __ata_port_probe(struct ata_port *ap) spin_unlock_irqrestore(ap->lock, flags); } -int ata_port_probe(struct ata_port *ap) -{ - __ata_port_probe(ap); - ata_port_wait_eh(ap); - return 0; -} - - static void async_port_probe(void *data, async_cookie_t cookie) { struct ata_port *ap = data; @@ -5906,7 +5898,8 @@ static void async_port_probe(void *data, async_cookie_t cookie) if (!(ap->host->flags & ATA_HOST_PARALLEL_SCAN) && ap->port_no != 0) async_synchronize_cookie(cookie); - (void)ata_port_probe(ap); + __ata_port_probe(ap); + ata_port_wait_eh(ap); /* in order to keep device order, we need to synchronize at this point */ async_synchronize_cookie(cookie); -- GitLab From a76f1b637ce92c2b8d5da912826079010b11f138 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 31 Jul 2023 16:34:17 +0200 Subject: [PATCH 0671/3445] ata,scsi: cleanup __ata_port_probe() Rename __ata_port_probe() to ata_port_probe() and drop the wrapper ata_sas_async_probe(). Signed-off-by: Hannes Reinecke Signed-off-by: Niklas Cassel Reviewed-by: Jason Yan Reviewed-by: John Garry Reviewed-by: Martin K. Petersen Signed-off-by: Damien Le Moal --- drivers/ata/libata-core.c | 5 +++-- drivers/ata/libata-sata.c | 13 ------------- drivers/ata/libata.h | 2 -- drivers/scsi/hisi_sas/hisi_sas_main.c | 2 +- drivers/scsi/libsas/sas_ata.c | 2 +- include/linux/libata.h | 2 +- 6 files changed, 6 insertions(+), 20 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index c6e624d27f46d..fdd4804d0bf28 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5865,7 +5865,7 @@ void ata_host_init(struct ata_host *host, struct device *dev, } EXPORT_SYMBOL_GPL(ata_host_init); -void __ata_port_probe(struct ata_port *ap) +void ata_port_probe(struct ata_port *ap) { struct ata_eh_info *ehi = &ap->link.eh_info; unsigned long flags; @@ -5883,6 +5883,7 @@ void __ata_port_probe(struct ata_port *ap) spin_unlock_irqrestore(ap->lock, flags); } +EXPORT_SYMBOL_GPL(ata_port_probe); static void async_port_probe(void *data, async_cookie_t cookie) { @@ -5898,7 +5899,7 @@ static void async_port_probe(void *data, async_cookie_t cookie) if (!(ap->host->flags & ATA_HOST_PARALLEL_SCAN) && ap->port_no != 0) async_synchronize_cookie(cookie); - __ata_port_probe(ap); + ata_port_probe(ap); ata_port_wait_eh(ap); /* in order to keep device order, we need to synchronize at this point */ diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index 04ab2bedcaa24..eb81641d383af 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -1144,19 +1144,6 @@ struct ata_port *ata_sas_port_alloc(struct ata_host *host, } EXPORT_SYMBOL_GPL(ata_sas_port_alloc); -/** - * ata_sas_async_probe - simply schedule probing and return - * @ap: Port to probe - * - * For batch scheduling of probe for sas attached ata devices, assumes - * the port has already been through ata_sas_port_init() - */ -void ata_sas_async_probe(struct ata_port *ap) -{ - __ata_port_probe(ap); -} -EXPORT_SYMBOL_GPL(ata_sas_async_probe); - /** * ata_sas_port_init - Initialize a SATA device * @ap: SATA port to initialize diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index cf993885d2b25..1ec9b4427b840 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -78,8 +78,6 @@ extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg); extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); extern struct ata_port *ata_port_alloc(struct ata_host *host); extern const char *sata_spd_string(unsigned int spd); -extern int ata_port_probe(struct ata_port *ap); -extern void __ata_port_probe(struct ata_port *ap); extern unsigned int ata_read_log_page(struct ata_device *dev, u8 log, u8 page, void *buf, unsigned int sectors); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 8f22ece957bd4..b2f07c6f30e7a 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -787,7 +787,7 @@ static int hisi_sas_init_device(struct domain_device *device) * However we don't need to issue a hard reset here for these * reasons: * a. When probing the device, libsas/libata already issues a - * hard reset in sas_probe_sata() -> ata_sas_async_probe(). + * hard reset in sas_probe_sata() -> ata_port_probe(). * Note that in hisi_sas_debug_I_T_nexus_reset() we take care * to issue a hard reset by checking the dev status (== INIT). * b. When resetting the controller, this is simply unnecessary. diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index a2eb9a2191c0f..d6bb37b3974ad 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -653,7 +653,7 @@ void sas_probe_sata(struct asd_sas_port *port) if (!dev_is_sata(dev)) continue; - ata_sas_async_probe(dev->sata_dev.ap); + ata_port_probe(dev->sata_dev.ap); } mutex_unlock(&port->ha->disco_mutex); diff --git a/include/linux/libata.h b/include/linux/libata.h index d08dde8c8ad2d..7468a330fc775 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1240,7 +1240,7 @@ extern int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy, extern int ata_slave_link_init(struct ata_port *ap); extern struct ata_port *ata_sas_port_alloc(struct ata_host *, struct ata_port_info *, struct Scsi_Host *); -extern void ata_sas_async_probe(struct ata_port *ap); +extern void ata_port_probe(struct ata_port *ap); extern int ata_sas_port_init(struct ata_port *); extern int ata_sas_tport_add(struct device *parent, struct ata_port *ap); extern void ata_sas_tport_delete(struct ata_port *ap); -- GitLab From 541528170a5cb1342c378dfd46b04dfe024dbc7a Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 31 Jul 2023 16:34:18 +0200 Subject: [PATCH 0672/3445] ata,scsi: remove ata_sas_port_init() ata_sas_port_init() now only contains a single initialization. Move this single initialization to ata_sas_port_alloc(), since: 1) ata_sas_port_alloc() already initializes some of the struct members. 2) ata_sas_port_alloc() is only used by libsas. Suggested-by: John Garry Signed-off-by: Niklas Cassel Reviewed-by: John Garry Reviewed-by: Martin K. Petersen Signed-off-by: Damien Le Moal --- drivers/ata/libata-sata.c | 19 +------------------ drivers/scsi/libsas/sas_ata.c | 3 --- include/linux/libata.h | 1 - 3 files changed, 1 insertion(+), 22 deletions(-) diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index eb81641d383af..5d31c08be0136 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -1139,29 +1139,12 @@ struct ata_port *ata_sas_port_alloc(struct ata_host *host, ap->flags |= port_info->flags; ap->ops = port_info->port_ops; ap->cbl = ATA_CBL_SATA; + ap->print_id = atomic_inc_return(&ata_print_id); return ap; } EXPORT_SYMBOL_GPL(ata_sas_port_alloc); -/** - * ata_sas_port_init - Initialize a SATA device - * @ap: SATA port to initialize - * - * LOCKING: - * PCI/etc. bus probe sem. - * - * RETURNS: - * Zero on success, non-zero on error. - */ - -int ata_sas_port_init(struct ata_port *ap) -{ - ap->print_id = atomic_inc_return(&ata_print_id); - return 0; -} -EXPORT_SYMBOL_GPL(ata_sas_port_init); - int ata_sas_tport_add(struct device *parent, struct ata_port *ap) { return ata_tport_add(parent, ap); diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index d6bb37b3974ad..cd16a1ac379d3 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -605,9 +605,6 @@ int sas_ata_init(struct domain_device *found_dev) ap->private_data = found_dev; ap->cbl = ATA_CBL_SATA; ap->scsi_host = shost; - rc = ata_sas_port_init(ap); - if (rc) - goto destroy_port; rc = ata_sas_tport_add(ata_host->dev, ap); if (rc) diff --git a/include/linux/libata.h b/include/linux/libata.h index 7468a330fc775..0980992c54c21 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1241,7 +1241,6 @@ extern int ata_slave_link_init(struct ata_port *ap); extern struct ata_port *ata_sas_port_alloc(struct ata_host *, struct ata_port_info *, struct Scsi_Host *); extern void ata_port_probe(struct ata_port *ap); -extern int ata_sas_port_init(struct ata_port *); extern int ata_sas_tport_add(struct device *parent, struct ata_port *ap); extern void ata_sas_tport_delete(struct ata_port *ap); extern int ata_sas_slave_configure(struct scsi_device *, struct ata_port *); -- GitLab From f810b81ce897b323e3cc5664194b92b67462d534 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 31 Jul 2023 16:34:19 +0200 Subject: [PATCH 0673/3445] ata: sata_sx4: drop already completed TODO The TODO claims that the pdc_20621_ops should set the .inherits function pointer to &ata_base_port_ops after it has been converted to use the new EH. However, the driver was converted to use the new EH a long time ago, in commit 67651ee5710c ("[libata] sata_sx4: convert to new exception handling methods"), which also did set .inherits function pointer to &ata_sff_port_ops (and ata_sff_port_ops itself has .inherits set to &ata_base_port_ops). Signed-off-by: Niklas Cassel Reviewed-by: Hannes Reinecke Reviewed-by: Jason Yan Reviewed-by: John Garry Reviewed-by: Martin K. Petersen Signed-off-by: Damien Le Moal --- drivers/ata/sata_sx4.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index ccc0160726372..b51d7a9d0d90c 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -232,7 +232,6 @@ static const struct scsi_host_template pdc_sata_sht = { .dma_boundary = ATA_DMA_BOUNDARY, }; -/* TODO: inherit from base port_ops after converting to new EH */ static struct ata_port_operations pdc_20621_ops = { .inherits = &ata_sff_port_ops, -- GitLab From 89329c7384ef56c407269157e30e781f55c3c4d2 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 31 Jul 2023 16:34:20 +0200 Subject: [PATCH 0674/3445] ata: libata-core: remove ata_bus_probe() Remove ata_bus_probe() as it is unused. Also, remove references to ata_bus_probe and port_disable in Documentation/driver-api/libata.rst, as neither exist anymore. Signed-off-by: Niklas Cassel Reviewed-by: John Garry Reviewed-by: Jason Yan Reviewed-by: Martin K. Petersen Signed-off-by: Damien Le Moal --- Documentation/driver-api/libata.rst | 16 ---- drivers/ata/libata-core.c | 138 ---------------------------- drivers/ata/libata.h | 1 - include/linux/libata.h | 1 - 4 files changed, 156 deletions(-) diff --git a/Documentation/driver-api/libata.rst b/Documentation/driver-api/libata.rst index 311af516a3fd9..eecb8b81e1858 100644 --- a/Documentation/driver-api/libata.rst +++ b/Documentation/driver-api/libata.rst @@ -32,22 +32,6 @@ register blocks. :c:type:`struct ata_port_operations ` ---------------------------------------------------------- -Disable ATA port -~~~~~~~~~~~~~~~~ - -:: - - void (*port_disable) (struct ata_port *); - - -Called from :c:func:`ata_bus_probe` error path, as well as when unregistering -from the SCSI module (rmmod, hot unplug). This function should do -whatever needs to be done to take the port out of use. In most cases, -:c:func:`ata_port_disable` can be used as this hook. - -Called from :c:func:`ata_bus_probe` on a failed probe. Called from -:c:func:`ata_scsi_release`. - Post-IDENTIFY device configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index fdd4804d0bf28..988d1fc451be6 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3057,144 +3057,6 @@ int ata_cable_sata(struct ata_port *ap) } EXPORT_SYMBOL_GPL(ata_cable_sata); -/** - * ata_bus_probe - Reset and probe ATA bus - * @ap: Bus to probe - * - * Master ATA bus probing function. Initiates a hardware-dependent - * bus reset, then attempts to identify any devices found on - * the bus. - * - * LOCKING: - * PCI/etc. bus probe sem. - * - * RETURNS: - * Zero on success, negative errno otherwise. - */ - -int ata_bus_probe(struct ata_port *ap) -{ - unsigned int classes[ATA_MAX_DEVICES]; - int tries[ATA_MAX_DEVICES]; - int rc; - struct ata_device *dev; - - ata_for_each_dev(dev, &ap->link, ALL) - tries[dev->devno] = ATA_PROBE_MAX_TRIES; - - retry: - ata_for_each_dev(dev, &ap->link, ALL) { - /* If we issue an SRST then an ATA drive (not ATAPI) - * may change configuration and be in PIO0 timing. If - * we do a hard reset (or are coming from power on) - * this is true for ATA or ATAPI. Until we've set a - * suitable controller mode we should not touch the - * bus as we may be talking too fast. - */ - dev->pio_mode = XFER_PIO_0; - dev->dma_mode = 0xff; - - /* If the controller has a pio mode setup function - * then use it to set the chipset to rights. Don't - * touch the DMA setup as that will be dealt with when - * configuring devices. - */ - if (ap->ops->set_piomode) - ap->ops->set_piomode(ap, dev); - } - - /* reset and determine device classes */ - ap->ops->phy_reset(ap); - - ata_for_each_dev(dev, &ap->link, ALL) { - if (dev->class != ATA_DEV_UNKNOWN) - classes[dev->devno] = dev->class; - else - classes[dev->devno] = ATA_DEV_NONE; - - dev->class = ATA_DEV_UNKNOWN; - } - - /* read IDENTIFY page and configure devices. We have to do the identify - specific sequence bass-ackwards so that PDIAG- is released by - the slave device */ - - ata_for_each_dev(dev, &ap->link, ALL_REVERSE) { - if (tries[dev->devno]) - dev->class = classes[dev->devno]; - - if (!ata_dev_enabled(dev)) - continue; - - rc = ata_dev_read_id(dev, &dev->class, ATA_READID_POSTRESET, - dev->id); - if (rc) - goto fail; - } - - /* Now ask for the cable type as PDIAG- should have been released */ - if (ap->ops->cable_detect) - ap->cbl = ap->ops->cable_detect(ap); - - /* We may have SATA bridge glue hiding here irrespective of - * the reported cable types and sensed types. When SATA - * drives indicate we have a bridge, we don't know which end - * of the link the bridge is which is a problem. - */ - ata_for_each_dev(dev, &ap->link, ENABLED) - if (ata_id_is_sata(dev->id)) - ap->cbl = ATA_CBL_SATA; - - /* After the identify sequence we can now set up the devices. We do - this in the normal order so that the user doesn't get confused */ - - ata_for_each_dev(dev, &ap->link, ENABLED) { - ap->link.eh_context.i.flags |= ATA_EHI_PRINTINFO; - rc = ata_dev_configure(dev); - ap->link.eh_context.i.flags &= ~ATA_EHI_PRINTINFO; - if (rc) - goto fail; - } - - /* configure transfer mode */ - rc = ata_set_mode(&ap->link, &dev); - if (rc) - goto fail; - - ata_for_each_dev(dev, &ap->link, ENABLED) - return 0; - - return -ENODEV; - - fail: - tries[dev->devno]--; - - switch (rc) { - case -EINVAL: - /* eeek, something went very wrong, give up */ - tries[dev->devno] = 0; - break; - - case -ENODEV: - /* give it just one more chance */ - tries[dev->devno] = min(tries[dev->devno], 1); - fallthrough; - case -EIO: - if (tries[dev->devno] == 1) { - /* This is the last chance, better to slow - * down than lose it. - */ - sata_down_spd_limit(&ap->link, 0); - ata_down_xfermask_limit(dev, ATA_DNXFER_PIO); - } - } - - if (!tries[dev->devno]) - ata_dev_disable(dev); - - goto retry; -} - /** * sata_print_link_status - Print SATA link status * @link: SATA link to printk link status about diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 1ec9b4427b840..6e7d352803bd4 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -122,7 +122,6 @@ extern void ata_scsi_media_change_notify(struct ata_device *dev); extern void ata_scsi_hotplug(struct work_struct *work); extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); extern void ata_scsi_dev_rescan(struct work_struct *work); -extern int ata_bus_probe(struct ata_port *ap); extern int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, unsigned int id, u64 lun); void ata_scsi_sdev_config(struct scsi_device *sdev); diff --git a/include/linux/libata.h b/include/linux/libata.h index 0980992c54c21..e176d832467dc 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -344,7 +344,6 @@ enum { ATA_LINK_RESUME_TRIES = 5, /* how hard are we gonna try to probe/recover devices */ - ATA_PROBE_MAX_TRIES = 3, ATA_EH_DEV_TRIES = 3, ATA_EH_PMP_TRIES = 5, ATA_EH_PMP_LINK_TRIES = 3, -- GitLab From 6b4f165e0858016f7bb5f360966882a819519f07 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 31 Jul 2023 16:34:21 +0200 Subject: [PATCH 0675/3445] ata: libata: remove deprecated EH callbacks Now that all libata drivers have migrated to use the error_handler callback, remove the deprecated phy_reset and eng_timeout callbacks. Also remove references to non-existent functions sata_phy_reset and ata_qc_timeout from Documentation/driver-api/libata.rst. Signed-off-by: Niklas Cassel Reviewed-by: John Garry Reviewed-by: Sergey Shtylyov Reviewed-by: Jason Yan Reviewed-by: Martin K. Petersen Signed-off-by: Damien Le Moal --- Documentation/driver-api/libata.rst | 22 ++++++---------------- drivers/ata/pata_sl82c105.c | 3 +-- include/linux/libata.h | 6 ------ 3 files changed, 7 insertions(+), 24 deletions(-) diff --git a/Documentation/driver-api/libata.rst b/Documentation/driver-api/libata.rst index eecb8b81e1858..5da27a749246e 100644 --- a/Documentation/driver-api/libata.rst +++ b/Documentation/driver-api/libata.rst @@ -256,14 +256,6 @@ advanced drivers implement their own ``->qc_issue``. Exception and probe handling (EH) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -:: - - void (*eng_timeout) (struct ata_port *ap); - void (*phy_reset) (struct ata_port *ap); - - -Deprecated. Use ``->error_handler()`` instead. - :: void (*freeze) (struct ata_port *ap); @@ -348,8 +340,7 @@ SATA phy read/write u32 val); -Read and write standard SATA phy registers. Currently only used if -``->phy_reset`` hook called the :c:func:`sata_phy_reset` helper function. +Read and write standard SATA phy registers. sc_reg is one of SCR_STATUS, SCR_CONTROL, SCR_ERROR, or SCR_ACTIVE. Init and shutdown @@ -520,13 +511,12 @@ to return without deallocating the qc. This leads us to :c:func:`ata_scsi_error` is the current ``transportt->eh_strategy_handler()`` for libata. As discussed above, this will be entered in two cases - -timeout and ATAPI error completion. This function calls low level libata -driver's :c:func:`eng_timeout` callback, the standard callback for which is -:c:func:`ata_eng_timeout`. It checks if a qc is active and calls -:c:func:`ata_qc_timeout` on the qc if so. Actual error handling occurs in -:c:func:`ata_qc_timeout`. +timeout and ATAPI error completion. This function will check if a qc is active +and has not failed yet. Such a qc will be marked with AC_ERR_TIMEOUT such that +EH will know to handle it later. Then it calls low level libata driver's +:c:func:`error_handler` callback. -If EH is invoked for timeout, :c:func:`ata_qc_timeout` stops BMDMA and +When the :c:func:`error_handler` callback is invoked it stops BMDMA and completes the qc. Note that as we're currently in EH, we cannot call scsi_done. As described in SCSI EH doc, a recovered scmd should be either retried with :c:func:`scsi_queue_insert` or finished with diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index 3b62ea482f1ab..93882e976ede4 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -180,8 +180,7 @@ static void sl82c105_bmdma_start(struct ata_queued_cmd *qc) * document. * * This function is also called to turn off DMA when a timeout occurs - * during DMA operation. In both cases we need to reset the engine, - * so no actual eng_timeout handler is required. + * during DMA operation. In both cases we need to reset the engine. * * We assume bmdma_stop is always called if bmdma_start as called. If * not then we may need to wrap qc_issue. diff --git a/include/linux/libata.h b/include/linux/libata.h index e176d832467dc..52d58b13e5eee 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -975,12 +975,6 @@ struct ata_port_operations { ssize_t (*transmit_led_message)(struct ata_port *ap, u32 state, ssize_t size); - /* - * Obsolete - */ - void (*phy_reset)(struct ata_port *ap); - void (*eng_timeout)(struct ata_port *ap); - /* * ->inherits must be the last field and all the preceding * fields must be pointers. -- GitLab From 843b62f41cff687756ca54c88f9fddc676a3ee36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 31 Jul 2023 11:16:25 +0200 Subject: [PATCH 0676/3445] ata: pata_arasan_cf: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Viresh Kumar Reviewed-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- drivers/ata/pata_arasan_cf.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c index 314eaa1679540..d0c6924d25b67 100644 --- a/drivers/ata/pata_arasan_cf.c +++ b/drivers/ata/pata_arasan_cf.c @@ -917,15 +917,13 @@ static int arasan_cf_probe(struct platform_device *pdev) return ret; } -static int arasan_cf_remove(struct platform_device *pdev) +static void arasan_cf_remove(struct platform_device *pdev) { struct ata_host *host = platform_get_drvdata(pdev); struct arasan_cf_dev *acdev = host->ports[0]->private_data; ata_host_detach(host); cf_exit(acdev); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -966,7 +964,7 @@ MODULE_DEVICE_TABLE(of, arasan_cf_id_table); static struct platform_driver arasan_cf_driver = { .probe = arasan_cf_probe, - .remove = arasan_cf_remove, + .remove_new = arasan_cf_remove, .driver = { .name = DRIVER_NAME, .pm = &arasan_cf_pm_ops, -- GitLab From 3e981d936a715e368cbc8b951b3b6c985b0e2611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 31 Jul 2023 11:16:26 +0200 Subject: [PATCH 0677/3445] ata: pata_ep93xx: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- drivers/ata/pata_ep93xx.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c index c6e043e05d43b..744ad5e8cfbf3 100644 --- a/drivers/ata/pata_ep93xx.c +++ b/drivers/ata/pata_ep93xx.c @@ -1004,7 +1004,7 @@ err_rel_gpio: return err; } -static int ep93xx_pata_remove(struct platform_device *pdev) +static void ep93xx_pata_remove(struct platform_device *pdev) { struct ata_host *host = platform_get_drvdata(pdev); struct ep93xx_pata_data *drv_data = host->private_data; @@ -1013,7 +1013,6 @@ static int ep93xx_pata_remove(struct platform_device *pdev) ep93xx_pata_release_dma(drv_data); ep93xx_pata_clear_regs(drv_data->ide_base); ep93xx_ide_release_gpio(pdev); - return 0; } static struct platform_driver ep93xx_pata_platform_driver = { @@ -1021,7 +1020,7 @@ static struct platform_driver ep93xx_pata_platform_driver = { .name = DRV_NAME, }, .probe = ep93xx_pata_probe, - .remove = ep93xx_pata_remove, + .remove_new = ep93xx_pata_remove, }; module_platform_driver(ep93xx_pata_platform_driver); -- GitLab From 201025973d6367316bb2a9676178d425075f9f15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 31 Jul 2023 11:16:27 +0200 Subject: [PATCH 0678/3445] ata: pata_ftide010: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- drivers/ata/pata_ftide010.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/ata/pata_ftide010.c b/drivers/ata/pata_ftide010.c index ae455f3de18e1..d77ee40115aa9 100644 --- a/drivers/ata/pata_ftide010.c +++ b/drivers/ata/pata_ftide010.c @@ -536,15 +536,13 @@ err_dis_clk: return ret; } -static int pata_ftide010_remove(struct platform_device *pdev) +static void pata_ftide010_remove(struct platform_device *pdev) { struct ata_host *host = platform_get_drvdata(pdev); struct ftide010 *ftide = host->private_data; ata_host_detach(ftide->host); clk_disable_unprepare(ftide->pclk); - - return 0; } static const struct of_device_id pata_ftide010_of_match[] = { @@ -558,7 +556,7 @@ static struct platform_driver pata_ftide010_driver = { .of_match_table = pata_ftide010_of_match, }, .probe = pata_ftide010_probe, - .remove = pata_ftide010_remove, + .remove_new = pata_ftide010_remove, }; module_platform_driver(pata_ftide010_driver); -- GitLab From eb605fa6c97730e69daeb4381b43dd921250386a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 31 Jul 2023 11:16:28 +0200 Subject: [PATCH 0679/3445] ata: pata_imx: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- drivers/ata/pata_imx.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c index 65d09ec94c121..91da7ecec0fc0 100644 --- a/drivers/ata/pata_imx.c +++ b/drivers/ata/pata_imx.c @@ -203,7 +203,7 @@ err: return ret; } -static int pata_imx_remove(struct platform_device *pdev) +static void pata_imx_remove(struct platform_device *pdev) { struct ata_host *host = platform_get_drvdata(pdev); struct pata_imx_priv *priv = host->private_data; @@ -213,8 +213,6 @@ static int pata_imx_remove(struct platform_device *pdev) __raw_writel(0, priv->host_regs + PATA_IMX_ATA_INT_EN); clk_disable_unprepare(priv->clk); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -265,7 +263,7 @@ MODULE_DEVICE_TABLE(of, imx_pata_dt_ids); static struct platform_driver pata_imx_driver = { .probe = pata_imx_probe, - .remove = pata_imx_remove, + .remove_new = pata_imx_remove, .driver = { .name = DRV_NAME, .of_match_table = imx_pata_dt_ids, -- GitLab From b5ba32b63c11d9e6abc2349f54fe9cbb606d5779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 31 Jul 2023 11:16:29 +0200 Subject: [PATCH 0680/3445] ata: pata_mpc52xx: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- drivers/ata/pata_mpc52xx.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index 56fad9a5bc653..6c317a461a1f6 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -801,8 +801,7 @@ static int mpc52xx_ata_probe(struct platform_device *op) return rv; } -static int -mpc52xx_ata_remove(struct platform_device *op) +static void mpc52xx_ata_remove(struct platform_device *op) { struct ata_host *host = platform_get_drvdata(op); struct mpc52xx_ata_priv *priv = host->private_data; @@ -816,8 +815,6 @@ mpc52xx_ata_remove(struct platform_device *op) irq_dispose_mapping(task_irq); bcom_ata_release(priv->dmatsk); irq_dispose_mapping(priv->ata_irq); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -858,7 +855,7 @@ static const struct of_device_id mpc52xx_ata_of_match[] = { static struct platform_driver mpc52xx_ata_of_platform_driver = { .probe = mpc52xx_ata_probe, - .remove = mpc52xx_ata_remove, + .remove_new = mpc52xx_ata_remove, #ifdef CONFIG_PM_SLEEP .suspend = mpc52xx_ata_suspend, .resume = mpc52xx_ata_resume, -- GitLab From 4b1d88fcbf9b93e2fc046f0e19d3e31334cfb74b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 31 Jul 2023 11:16:30 +0200 Subject: [PATCH 0681/3445] ata: pata_pxa: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- drivers/ata/pata_pxa.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/ata/pata_pxa.c b/drivers/ata/pata_pxa.c index ea402e02c46e2..5275c6464f57f 100644 --- a/drivers/ata/pata_pxa.c +++ b/drivers/ata/pata_pxa.c @@ -295,7 +295,7 @@ static int pxa_ata_probe(struct platform_device *pdev) return ret; } -static int pxa_ata_remove(struct platform_device *pdev) +static void pxa_ata_remove(struct platform_device *pdev) { struct ata_host *host = platform_get_drvdata(pdev); struct pata_pxa_data *data = host->ports[0]->private_data; @@ -303,13 +303,11 @@ static int pxa_ata_remove(struct platform_device *pdev) dma_release_channel(data->dma_chan); ata_host_detach(host); - - return 0; } static struct platform_driver pxa_ata_driver = { .probe = pxa_ata_probe, - .remove = pxa_ata_remove, + .remove_new = pxa_ata_remove, .driver = { .name = DRV_NAME, }, -- GitLab From d6ef90f1c0e479d84e3000fea117521c26b61d7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 31 Jul 2023 11:16:31 +0200 Subject: [PATCH 0682/3445] ata: pata_rb532_cf: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- drivers/ata/pata_rb532_cf.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/ata/pata_rb532_cf.c b/drivers/ata/pata_rb532_cf.c index 3974d294a341b..0fa253ad7c93e 100644 --- a/drivers/ata/pata_rb532_cf.c +++ b/drivers/ata/pata_rb532_cf.c @@ -155,18 +155,16 @@ static int rb532_pata_driver_probe(struct platform_device *pdev) return 0; } -static int rb532_pata_driver_remove(struct platform_device *pdev) +static void rb532_pata_driver_remove(struct platform_device *pdev) { struct ata_host *ah = platform_get_drvdata(pdev); ata_host_detach(ah); - - return 0; } static struct platform_driver rb532_pata_platform_driver = { .probe = rb532_pata_driver_probe, - .remove = rb532_pata_driver_remove, + .remove_new = rb532_pata_driver_remove, .driver = { .name = DRV_NAME, }, -- GitLab From ac1bc5f957c1f5eef6b8aba48e585c06d83509a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 31 Jul 2023 11:16:32 +0200 Subject: [PATCH 0683/3445] ata: sata_dwc_460ex: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Damien Le Moal --- drivers/ata/sata_dwc_460ex.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index d699c5f35153d..52f5168e4db54 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -1210,7 +1210,7 @@ error_out: return err; } -static int sata_dwc_remove(struct platform_device *ofdev) +static void sata_dwc_remove(struct platform_device *ofdev) { struct device *dev = &ofdev->dev; struct ata_host *host = dev_get_drvdata(dev); @@ -1226,7 +1226,6 @@ static int sata_dwc_remove(struct platform_device *ofdev) #endif dev_dbg(dev, "done\n"); - return 0; } static const struct of_device_id sata_dwc_match[] = { @@ -1241,7 +1240,7 @@ static struct platform_driver sata_dwc_driver = { .of_match_table = sata_dwc_match, }, .probe = sata_dwc_probe, - .remove = sata_dwc_remove, + .remove_new = sata_dwc_remove, }; module_platform_driver(sata_dwc_driver); -- GitLab From 1a9bc02bbe671becdd615ea56333dc45388853ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 31 Jul 2023 11:16:33 +0200 Subject: [PATCH 0684/3445] ata: sata_fsl: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Damien Le Moal --- drivers/ata/sata_fsl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 16415eb093023..01aa05f4c3f5c 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -1526,7 +1526,7 @@ error_exit_with_cleanup: return retval; } -static int sata_fsl_remove(struct platform_device *ofdev) +static void sata_fsl_remove(struct platform_device *ofdev) { struct ata_host *host = platform_get_drvdata(ofdev); struct sata_fsl_host_priv *host_priv = host->private_data; @@ -1535,8 +1535,6 @@ static int sata_fsl_remove(struct platform_device *ofdev) device_remove_file(&ofdev->dev, &host_priv->rx_watermark); ata_host_detach(host); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -1591,7 +1589,7 @@ static struct platform_driver fsl_sata_driver = { .of_match_table = fsl_sata_match, }, .probe = sata_fsl_probe, - .remove = sata_fsl_remove, + .remove_new = sata_fsl_remove, #ifdef CONFIG_PM_SLEEP .suspend = sata_fsl_suspend, .resume = sata_fsl_resume, -- GitLab From 114dda82d39bb86faec066930a8fd29cc2a922cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 31 Jul 2023 11:16:34 +0200 Subject: [PATCH 0685/3445] ata: sata_gemini: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Damien Le Moal --- drivers/ata/sata_gemini.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/ata/sata_gemini.c b/drivers/ata/sata_gemini.c index ca56d43df1493..6bc3bffa83cd0 100644 --- a/drivers/ata/sata_gemini.c +++ b/drivers/ata/sata_gemini.c @@ -399,7 +399,7 @@ out_unprep_clk: return ret; } -static int gemini_sata_remove(struct platform_device *pdev) +static void gemini_sata_remove(struct platform_device *pdev) { struct sata_gemini *sg = platform_get_drvdata(pdev); @@ -408,8 +408,6 @@ static int gemini_sata_remove(struct platform_device *pdev) clk_unprepare(sg->sata0_pclk); } sg_singleton = NULL; - - return 0; } static const struct of_device_id gemini_sata_of_match[] = { @@ -423,7 +421,7 @@ static struct platform_driver gemini_sata_driver = { .of_match_table = gemini_sata_of_match, }, .probe = gemini_sata_probe, - .remove = gemini_sata_remove, + .remove_new = gemini_sata_remove, }; module_platform_driver(gemini_sata_driver); -- GitLab From 3596b025627cdc84ac8c31b299a73cc0c350ed93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 31 Jul 2023 11:16:35 +0200 Subject: [PATCH 0686/3445] ata: sata_mv: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Signed-off-by: Damien Le Moal --- drivers/ata/sata_mv.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 41c107e15c403..d105db5c7d81a 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -4210,7 +4210,7 @@ err: * A platform bus SATA device has been unplugged. Perform the needed * cleanup. Also called on module unload for any active devices. */ -static int mv_platform_remove(struct platform_device *pdev) +static void mv_platform_remove(struct platform_device *pdev) { struct ata_host *host = platform_get_drvdata(pdev); struct mv_host_priv *hpriv = host->private_data; @@ -4228,7 +4228,6 @@ static int mv_platform_remove(struct platform_device *pdev) } phy_power_off(hpriv->port_phys[port]); } - return 0; } #ifdef CONFIG_PM_SLEEP @@ -4284,7 +4283,7 @@ MODULE_DEVICE_TABLE(of, mv_sata_dt_ids); static struct platform_driver mv_platform_driver = { .probe = mv_platform_probe, - .remove = mv_platform_remove, + .remove_new = mv_platform_remove, .suspend = mv_platform_suspend, .resume = mv_platform_resume, .driver = { -- GitLab From caea958926c33c72fd1c91b892feca82314e27e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 31 Jul 2023 11:16:36 +0200 Subject: [PATCH 0687/3445] ata: sata_rcar: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- drivers/ata/sata_rcar.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c index 16ce4af3b8942..c1469d0768801 100644 --- a/drivers/ata/sata_rcar.c +++ b/drivers/ata/sata_rcar.c @@ -909,7 +909,7 @@ err_pm_put: return ret; } -static int sata_rcar_remove(struct platform_device *pdev) +static void sata_rcar_remove(struct platform_device *pdev) { struct ata_host *host = platform_get_drvdata(pdev); struct sata_rcar_priv *priv = host->private_data; @@ -925,8 +925,6 @@ static int sata_rcar_remove(struct platform_device *pdev) pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -1011,7 +1009,7 @@ static const struct dev_pm_ops sata_rcar_pm_ops = { static struct platform_driver sata_rcar_driver = { .probe = sata_rcar_probe, - .remove = sata_rcar_remove, + .remove_new = sata_rcar_remove, .driver = { .name = DRV_NAME, .of_match_table = sata_rcar_match, -- GitLab From 55a5956a55b453ccbfb3297bdf34091e23d47455 Mon Sep 17 00:00:00 2001 From: Kamalesh Babulal Date: Tue, 1 Aug 2023 12:52:14 +0530 Subject: [PATCH 0688/3445] cgroup: clean up printk() Convert the only printk() to use pr_*() helper. No functional change. Signed-off-by: Kamalesh Babulal Signed-off-by: Tejun Heo --- kernel/cgroup/cgroup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index c7aafb59ecf24..33b586db14ef1 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -6086,8 +6086,8 @@ int __init cgroup_init(void) continue; if (cgroup1_ssid_disabled(ssid)) - printk(KERN_INFO "Disabling %s control group subsystem in v1 mounts\n", - ss->name); + pr_info("Disabling %s control group subsystem in v1 mounts\n", + ss->name); cgrp_dfl_root.subsys_mask |= 1 << ss->id; -- GitLab From 05f76ae95e71149a9c7085c323d3f710dff22730 Mon Sep 17 00:00:00 2001 From: Cai Xinchen Date: Wed, 2 Aug 2023 03:04:12 +0000 Subject: [PATCH 0689/3445] cgroup/cpuset: fix kernel-doc Add kernel-doc of param @rotor to fix warnings: kernel/cgroup/cpuset.c:4162: warning: Function parameter or member 'rotor' not described in 'cpuset_spread_node' kernel/cgroup/cpuset.c:3771: warning: Function parameter or member 'work' not described in 'cpuset_hotplug_workfn' Signed-off-by: Cai Xinchen Acked-by: Waiman Long Signed-off-by: Tejun Heo --- kernel/cgroup/cpuset.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index b278b60ed788d..58ec88efa4f82 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -3753,6 +3753,7 @@ unlock: /** * cpuset_hotplug_workfn - handle CPU/memory hotunplug for a cpuset + * @work: unused * * This function is called after either CPU or memory configuration has * changed and updates cpuset accordingly. The top_cpuset is always @@ -4135,6 +4136,7 @@ bool cpuset_node_allowed(int node, gfp_t gfp_mask) /** * cpuset_spread_node() - On which node to begin search for a page + * @rotor: round robin rotor * * If a task is marked PF_SPREAD_PAGE or PF_SPREAD_SLAB (as for * tasks in a cpuset with is_spread_page or is_spread_slab set), -- GitLab From a2c15fece4b47e2e5a89a3bf273c9c6517c3e8a5 Mon Sep 17 00:00:00 2001 From: Miaohe Lin Date: Tue, 1 Aug 2023 20:40:34 +0800 Subject: [PATCH 0690/3445] cgroup: fix obsolete function name above css_free_rwork_fn() Since commit 8f36aaec9c92 ("cgroup: Use rcu_work instead of explicit rcu and work item"), css_free_work_fn has been renamed to css_free_rwork_fn. Update corresponding comment. Signed-off-by: Miaohe Lin Signed-off-by: Tejun Heo --- kernel/cgroup/cgroup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 33b586db14ef1..f9cde56cf9475 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -5301,7 +5301,7 @@ static struct cftype cgroup_psi_files[] = { * RCU callback. * * 4. After the grace period, the css can be freed. Implemented in - * css_free_work_fn(). + * css_free_rwork_fn(). * * It is actually hairier because both step 2 and 4 require process context * and thus involve punting to css->destroy_work adding two additional -- GitLab From 0d033770d43a7aa36025bcef9a60da7fb750f735 Mon Sep 17 00:00:00 2001 From: Michal Luczaj Date: Fri, 28 Jul 2023 02:12:57 +0200 Subject: [PATCH 0691/3445] KVM: x86: Fix KVM_CAP_SYNC_REGS's sync_regs() TOCTOU issues In a spirit of using a sledgehammer to crack a nut, make sync_regs() feed __set_sregs() and kvm_vcpu_ioctl_x86_set_vcpu_events() with kernel's own copy of data. Both __set_sregs() and kvm_vcpu_ioctl_x86_set_vcpu_events() assume they have exclusive rights to structs they operate on. While this is true when coming from an ioctl handler (caller makes a local copy of user's data), sync_regs() breaks this contract; a pointer to a user-modifiable memory (vcpu->run->s.regs) is provided. This can lead to a situation when incoming data is checked and/or sanitized only to be re-set by a user thread running in parallel. Signed-off-by: Michal Luczaj Fixes: 01643c51bfcf ("KVM: x86: KVM_CAP_SYNC_REGS") Link: https://lore.kernel.org/r/20230728001606.2275586-2-mhal@rbox.co Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a6b9bea62fb8a..0145d844283be 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -11777,15 +11777,22 @@ static int sync_regs(struct kvm_vcpu *vcpu) __set_regs(vcpu, &vcpu->run->s.regs.regs); vcpu->run->kvm_dirty_regs &= ~KVM_SYNC_X86_REGS; } + if (vcpu->run->kvm_dirty_regs & KVM_SYNC_X86_SREGS) { - if (__set_sregs(vcpu, &vcpu->run->s.regs.sregs)) + struct kvm_sregs sregs = vcpu->run->s.regs.sregs; + + if (__set_sregs(vcpu, &sregs)) return -EINVAL; + vcpu->run->kvm_dirty_regs &= ~KVM_SYNC_X86_SREGS; } + if (vcpu->run->kvm_dirty_regs & KVM_SYNC_X86_EVENTS) { - if (kvm_vcpu_ioctl_x86_set_vcpu_events( - vcpu, &vcpu->run->s.regs.events)) + struct kvm_vcpu_events events = vcpu->run->s.regs.events; + + if (kvm_vcpu_ioctl_x86_set_vcpu_events(vcpu, &events)) return -EINVAL; + vcpu->run->kvm_dirty_regs &= ~KVM_SYNC_X86_EVENTS; } -- GitLab From ae895cbe613a5b193f3953c90c075306bfa4d30b Mon Sep 17 00:00:00 2001 From: Michal Luczaj Date: Fri, 28 Jul 2023 02:12:58 +0200 Subject: [PATCH 0692/3445] KVM: selftests: Extend x86's sync_regs_test to check for CR4 races Attempt to modify vcpu->run->s.regs _after_ the sanity checks performed by KVM_CAP_SYNC_REGS's arch/x86/kvm/x86.c:sync_regs(). This can lead to some nonsensical vCPU states accompanied by kernel splats, e.g. disabling PAE while long mode is enabled makes KVM all kinds of confused: WARNING: CPU: 0 PID: 1142 at arch/x86/kvm/mmu/paging_tmpl.h:358 paging32_walk_addr_generic+0x431/0x8f0 [kvm] arch/x86/kvm/mmu/paging_tmpl.h: KVM_BUG_ON(is_long_mode(vcpu) && !is_pae(vcpu), vcpu->kvm) Signed-off-by: Michal Luczaj Link: https://lore.kernel.org/r/20230728001606.2275586-3-mhal@rbox.co [sean: see link] Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/sync_regs_test.c | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/tools/testing/selftests/kvm/x86_64/sync_regs_test.c b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c index 2da89fdc2471a..13ac3ae8e7046 100644 --- a/tools/testing/selftests/kvm/x86_64/sync_regs_test.c +++ b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "test_util.h" #include "kvm_util.h" @@ -80,6 +81,75 @@ static void compare_vcpu_events(struct kvm_vcpu_events *left, #define TEST_SYNC_FIELDS (KVM_SYNC_X86_REGS|KVM_SYNC_X86_SREGS|KVM_SYNC_X86_EVENTS) #define INVALID_SYNC_FIELD 0x80000000 +/* + * Toggle CR4.PAE while KVM is processing SREGS, EFER.LME=1 with CR4.PAE=0 is + * illegal, and KVM's MMU heavily relies on vCPU state being valid. + */ +static noinline void *race_sregs_cr4(void *arg) +{ + struct kvm_run *run = (struct kvm_run *)arg; + __u64 *cr4 = &run->s.regs.sregs.cr4; + __u64 pae_enabled = *cr4; + __u64 pae_disabled = *cr4 & ~X86_CR4_PAE; + + for (;;) { + WRITE_ONCE(run->kvm_dirty_regs, KVM_SYNC_X86_SREGS); + WRITE_ONCE(*cr4, pae_enabled); + asm volatile(".rept 512\n\t" + "nop\n\t" + ".endr"); + WRITE_ONCE(*cr4, pae_disabled); + + pthread_testcancel(); + } + + return NULL; +} + +static void race_sync_regs(void *racer) +{ + const time_t TIMEOUT = 2; /* seconds, roughly */ + struct kvm_translation tr; + struct kvm_vcpu *vcpu; + struct kvm_run *run; + struct kvm_vm *vm; + pthread_t thread; + time_t t; + + vm = vm_create_with_one_vcpu(&vcpu, guest_code); + run = vcpu->run; + + run->kvm_valid_regs = KVM_SYNC_X86_SREGS; + vcpu_run(vcpu); + run->kvm_valid_regs = 0; + + /* + * Selftests run 64-bit guests by default, both EFER.LME and CR4.PAE + * should already be set in guest state. + */ + TEST_ASSERT((run->s.regs.sregs.cr4 & X86_CR4_PAE) && + (run->s.regs.sregs.efer & EFER_LME), + "vCPU should be in long mode, CR4.PAE=%d, EFER.LME=%d", + !!(run->s.regs.sregs.cr4 & X86_CR4_PAE), + !!(run->s.regs.sregs.efer & EFER_LME)); + + ASSERT_EQ(pthread_create(&thread, NULL, racer, (void *)run), 0); + + for (t = time(NULL) + TIMEOUT; time(NULL) < t;) { + __vcpu_run(vcpu); + + if (racer == race_sregs_cr4) { + tr = (struct kvm_translation) { .linear_address = 0 }; + __vcpu_ioctl(vcpu, KVM_TRANSLATE, &tr); + } + } + + ASSERT_EQ(pthread_cancel(thread), 0); + ASSERT_EQ(pthread_join(thread, NULL), 0); + + kvm_vm_free(vm); +} + int main(int argc, char *argv[]) { struct kvm_vcpu *vcpu; @@ -218,5 +288,7 @@ int main(int argc, char *argv[]) kvm_vm_free(vm); + race_sync_regs(race_sregs_cr4); + return 0; } -- GitLab From 60c4063b475215321fc63ab253c9a840bb664f35 Mon Sep 17 00:00:00 2001 From: Michal Luczaj Date: Fri, 28 Jul 2023 02:12:58 +0200 Subject: [PATCH 0693/3445] KVM: selftests: Extend x86's sync_regs_test to check for event vector races Attempt to modify the to-be-injected exception vector to an illegal value _after_ the sanity checks performed by KVM_CAP_SYNC_REGS's arch/x86/kvm/x86.c:kvm_vcpu_ioctl_x86_set_vcpu_events(). Buggy KVM versions will eventually yells loudly about attempting to inject a bogus vector, e.g. WARNING: CPU: 0 PID: 1107 at arch/x86/kvm/x86.c:547 kvm_check_and_inject_events+0x4a0/0x500 [kvm] arch/x86/kvm/x86.c:exception_type(): WARN_ON(vector > 31 || vector == NMI_VECTOR) Signed-off-by: Michal Luczaj Link: https://lore.kernel.org/r/20230728001606.2275586-3-mhal@rbox.co [sean: split to separate patch] Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/sync_regs_test.c | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tools/testing/selftests/kvm/x86_64/sync_regs_test.c b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c index 13ac3ae8e7046..e4ff2eaad7cd3 100644 --- a/tools/testing/selftests/kvm/x86_64/sync_regs_test.c +++ b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c @@ -81,6 +81,27 @@ static void compare_vcpu_events(struct kvm_vcpu_events *left, #define TEST_SYNC_FIELDS (KVM_SYNC_X86_REGS|KVM_SYNC_X86_SREGS|KVM_SYNC_X86_EVENTS) #define INVALID_SYNC_FIELD 0x80000000 +/* + * Set an invalid exception vector while KVM is processing events. KVM is + * supposed to reject any vector >= 32, as well as NMIs (vector 2). + */ +static void *race_events_exc(void *arg) +{ + struct kvm_run *run = (struct kvm_run *)arg; + struct kvm_vcpu_events *events = &run->s.regs.events; + + for (;;) { + WRITE_ONCE(run->kvm_dirty_regs, KVM_SYNC_X86_EVENTS); + WRITE_ONCE(events->flags, 0); + WRITE_ONCE(events->exception.pending, 1); + WRITE_ONCE(events->exception.nr, 255); + + pthread_testcancel(); + } + + return NULL; +} + /* * Toggle CR4.PAE while KVM is processing SREGS, EFER.LME=1 with CR4.PAE=0 is * illegal, and KVM's MMU heavily relies on vCPU state being valid. @@ -289,6 +310,7 @@ int main(int argc, char *argv[]) kvm_vm_free(vm); race_sync_regs(race_sregs_cr4); + race_sync_regs(race_events_exc); return 0; } -- GitLab From 0de704d2d6c82c7498fa1b8df66903f8139e3de2 Mon Sep 17 00:00:00 2001 From: Michal Luczaj Date: Fri, 28 Jul 2023 02:12:58 +0200 Subject: [PATCH 0694/3445] KVM: selftests: Extend x86's sync_regs_test to check for exception races Attempt to set the to-be-queued exception to be both pending and injected _after_ KVM_CAP_SYNC_REGS's kvm_vcpu_ioctl_x86_set_vcpu_events() squashes the pending exception (if there's also an injected exception). Buggy KVM versions will eventually yell loudly about having impossible state when processing queued excpetions, e.g. WARNING: CPU: 0 PID: 1115 at arch/x86/kvm/x86.c:10095 kvm_check_and_inject_events+0x220/0x500 [kvm] arch/x86/kvm/x86.c:kvm_check_and_inject_events(): WARN_ON_ONCE(vcpu->arch.exception.injected && vcpu->arch.exception.pending); Signed-off-by: Michal Luczaj Link: https://lore.kernel.org/r/20230728001606.2275586-3-mhal@rbox.co [sean: split to separate patch, massage changelog and comment] Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/sync_regs_test.c | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tools/testing/selftests/kvm/x86_64/sync_regs_test.c b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c index e4ff2eaad7cd3..7e5b13869e2e7 100644 --- a/tools/testing/selftests/kvm/x86_64/sync_regs_test.c +++ b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c @@ -81,6 +81,28 @@ static void compare_vcpu_events(struct kvm_vcpu_events *left, #define TEST_SYNC_FIELDS (KVM_SYNC_X86_REGS|KVM_SYNC_X86_SREGS|KVM_SYNC_X86_EVENTS) #define INVALID_SYNC_FIELD 0x80000000 +/* + * Set an exception as pending *and* injected while KVM is processing events. + * KVM is supposed to ignore/drop pending exceptions if userspace is also + * requesting that an exception be injected. + */ +static void *race_events_inj_pen(void *arg) +{ + struct kvm_run *run = (struct kvm_run *)arg; + struct kvm_vcpu_events *events = &run->s.regs.events; + + for (;;) { + WRITE_ONCE(run->kvm_dirty_regs, KVM_SYNC_X86_EVENTS); + WRITE_ONCE(events->flags, 0); + WRITE_ONCE(events->exception.injected, 1); + WRITE_ONCE(events->exception.pending, 1); + + pthread_testcancel(); + } + + return NULL; +} + /* * Set an invalid exception vector while KVM is processing events. KVM is * supposed to reject any vector >= 32, as well as NMIs (vector 2). @@ -311,6 +333,7 @@ int main(int argc, char *argv[]) race_sync_regs(race_sregs_cr4); race_sync_regs(race_events_exc); + race_sync_regs(race_events_inj_pen); return 0; } -- GitLab From b859b018aadfd05f0526533fd1bcf04024d01917 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Mon, 31 Jul 2023 10:24:05 +0800 Subject: [PATCH 0695/3445] KVM: selftests: use unified time type for comparison With test case kvm_page_table_test, start time is acquired with time type CLOCK_MONOTONIC_RAW, however end time in timespec_elapsed() is acquired with time type CLOCK_MONOTONIC. This can cause inaccurate elapsed time calculation due to mixing timebases, e.g. LoongArch in particular will see weirdness. Modify kvm_page_table_test to use unified time type CLOCK_MONOTONIC for start time. Signed-off-by: Bibo Mao Reviewed-by: Oliver Upton Link: https://lore.kernel.org/r/20230731022405.854884-1-maobibo@loongson.cn [sean: massage changelog] Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/kvm_page_table_test.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/kvm/kvm_page_table_test.c b/tools/testing/selftests/kvm/kvm_page_table_test.c index b3b00be1ef824..69f26d80c8216 100644 --- a/tools/testing/selftests/kvm/kvm_page_table_test.c +++ b/tools/testing/selftests/kvm/kvm_page_table_test.c @@ -200,7 +200,7 @@ static void *vcpu_worker(void *data) if (READ_ONCE(host_quit)) return NULL; - clock_gettime(CLOCK_MONOTONIC_RAW, &start); + clock_gettime(CLOCK_MONOTONIC, &start); ret = _vcpu_run(vcpu); ts_diff = timespec_elapsed(start); @@ -367,7 +367,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) /* Test the stage of KVM creating mappings */ *current_stage = KVM_CREATE_MAPPINGS; - clock_gettime(CLOCK_MONOTONIC_RAW, &start); + clock_gettime(CLOCK_MONOTONIC, &start); vcpus_complete_new_stage(*current_stage); ts_diff = timespec_elapsed(start); @@ -380,7 +380,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) *current_stage = KVM_UPDATE_MAPPINGS; - clock_gettime(CLOCK_MONOTONIC_RAW, &start); + clock_gettime(CLOCK_MONOTONIC, &start); vcpus_complete_new_stage(*current_stage); ts_diff = timespec_elapsed(start); @@ -392,7 +392,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) *current_stage = KVM_ADJUST_MAPPINGS; - clock_gettime(CLOCK_MONOTONIC_RAW, &start); + clock_gettime(CLOCK_MONOTONIC, &start); vcpus_complete_new_stage(*current_stage); ts_diff = timespec_elapsed(start); -- GitLab From 7e4966e6e13d0dad5eae934aff8b875a2aa8f469 Mon Sep 17 00:00:00 2001 From: Minjie Du Date: Tue, 4 Jul 2023 20:21:47 +0800 Subject: [PATCH 0696/3445] KVM: selftests: Remove superfluous variable assignment Don't nullify "nodep" to NULL one line before it's set to "tmp". Signed-off-by: Minjie Du Link: https://lore.kernel.org/r/20230704122148.11573-1-duminjie@vivo.com [sean: massage shortlog+changelog] Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/lib/sparsebit.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/testing/selftests/kvm/lib/sparsebit.c b/tools/testing/selftests/kvm/lib/sparsebit.c index 50e0cf41a7dd6..88cb6b84e6f31 100644 --- a/tools/testing/selftests/kvm/lib/sparsebit.c +++ b/tools/testing/selftests/kvm/lib/sparsebit.c @@ -634,7 +634,6 @@ static void node_reduce(struct sparsebit *s, struct node *nodep) tmp = node_prev(s, nodep); node_rm(s, nodep); - nodep = NULL; nodep = tmp; reduction_performed = true; -- GitLab From 6d85f51a1f08411617d0bfe12c537ed6eba7f0f4 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 12 Jul 2023 09:59:07 +0200 Subject: [PATCH 0697/3445] KVM: selftests: Rename the ASSERT_EQ macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is already an ASSERT_EQ macro in the file tools/testing/selftests/kselftest_harness.h, so currently KVM selftests can't include test_util.h from the KVM selftests together with that file. Rename the macro in the KVM selftests to TEST_ASSERT_EQ to avoid the problem - it is also more similar to the other macros in test_util.h that way. Suggested-by: Sean Christopherson Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/r/20230712075910.22480-2-thuth@redhat.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/aarch64/aarch32_id_regs.c | 8 +-- .../selftests/kvm/aarch64/page_fault_test.c | 10 +-- .../testing/selftests/kvm/include/test_util.h | 4 +- tools/testing/selftests/kvm/lib/kvm_util.c | 2 +- .../selftests/kvm/max_guest_memory_test.c | 2 +- tools/testing/selftests/kvm/s390x/cmma_test.c | 62 +++++++++---------- tools/testing/selftests/kvm/s390x/memop.c | 6 +- tools/testing/selftests/kvm/s390x/tprot.c | 4 +- .../x86_64/dirty_log_page_splitting_test.c | 18 +++--- .../x86_64/exit_on_emulation_failure_test.c | 2 +- .../kvm/x86_64/nested_exceptions_test.c | 12 ++-- .../kvm/x86_64/recalc_apic_map_test.c | 6 +- .../selftests/kvm/x86_64/sync_regs_test.c | 6 +- .../selftests/kvm/x86_64/tsc_msrs_test.c | 32 +++++----- .../vmx_exception_with_invalid_guest_state.c | 2 +- .../selftests/kvm/x86_64/vmx_pmu_caps_test.c | 3 +- .../selftests/kvm/x86_64/xapic_state_test.c | 8 +-- .../selftests/kvm/x86_64/xen_vmcall_test.c | 20 +++--- 18 files changed, 104 insertions(+), 103 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/aarch32_id_regs.c b/tools/testing/selftests/kvm/aarch64/aarch32_id_regs.c index 4951ac53d1f88..b90580840b228 100644 --- a/tools/testing/selftests/kvm/aarch64/aarch32_id_regs.c +++ b/tools/testing/selftests/kvm/aarch64/aarch32_id_regs.c @@ -98,7 +98,7 @@ static void test_user_raz_wi(struct kvm_vcpu *vcpu) uint64_t val; vcpu_get_reg(vcpu, reg_id, &val); - ASSERT_EQ(val, 0); + TEST_ASSERT_EQ(val, 0); /* * Expect the ioctl to succeed with no effect on the register @@ -107,7 +107,7 @@ static void test_user_raz_wi(struct kvm_vcpu *vcpu) vcpu_set_reg(vcpu, reg_id, BAD_ID_REG_VAL); vcpu_get_reg(vcpu, reg_id, &val); - ASSERT_EQ(val, 0); + TEST_ASSERT_EQ(val, 0); } } @@ -127,14 +127,14 @@ static void test_user_raz_invariant(struct kvm_vcpu *vcpu) uint64_t val; vcpu_get_reg(vcpu, reg_id, &val); - ASSERT_EQ(val, 0); + TEST_ASSERT_EQ(val, 0); r = __vcpu_set_reg(vcpu, reg_id, BAD_ID_REG_VAL); TEST_ASSERT(r < 0 && errno == EINVAL, "unexpected KVM_SET_ONE_REG error: r=%d, errno=%d", r, errno); vcpu_get_reg(vcpu, reg_id, &val); - ASSERT_EQ(val, 0); + TEST_ASSERT_EQ(val, 0); } } diff --git a/tools/testing/selftests/kvm/aarch64/page_fault_test.c b/tools/testing/selftests/kvm/aarch64/page_fault_test.c index df10f1ffa20d9..e5bb8767d2cb5 100644 --- a/tools/testing/selftests/kvm/aarch64/page_fault_test.c +++ b/tools/testing/selftests/kvm/aarch64/page_fault_test.c @@ -318,7 +318,7 @@ static int uffd_generic_handler(int uffd_mode, int uffd, struct uffd_msg *msg, TEST_ASSERT(uffd_mode == UFFDIO_REGISTER_MODE_MISSING, "The only expected UFFD mode is MISSING"); - ASSERT_EQ(addr, (uint64_t)args->hva); + TEST_ASSERT_EQ(addr, (uint64_t)args->hva); pr_debug("uffd fault: addr=%p write=%d\n", (void *)addr, !!(flags & UFFD_PAGEFAULT_FLAG_WRITE)); @@ -432,7 +432,7 @@ static void mmio_on_test_gpa_handler(struct kvm_vm *vm, struct kvm_run *run) region = vm_get_mem_region(vm, MEM_REGION_TEST_DATA); hva = (void *)region->region.userspace_addr; - ASSERT_EQ(run->mmio.phys_addr, region->region.guest_phys_addr); + TEST_ASSERT_EQ(run->mmio.phys_addr, region->region.guest_phys_addr); memcpy(hva, run->mmio.data, run->mmio.len); events.mmio_exits += 1; @@ -631,9 +631,9 @@ static void setup_default_handlers(struct test_desc *test) static void check_event_counts(struct test_desc *test) { - ASSERT_EQ(test->expected_events.uffd_faults, events.uffd_faults); - ASSERT_EQ(test->expected_events.mmio_exits, events.mmio_exits); - ASSERT_EQ(test->expected_events.fail_vcpu_runs, events.fail_vcpu_runs); + TEST_ASSERT_EQ(test->expected_events.uffd_faults, events.uffd_faults); + TEST_ASSERT_EQ(test->expected_events.mmio_exits, events.mmio_exits); + TEST_ASSERT_EQ(test->expected_events.fail_vcpu_runs, events.fail_vcpu_runs); } static void print_test_banner(enum vm_guest_mode mode, struct test_params *p) diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h index a6e9f215ce700..e734e52d8a3a6 100644 --- a/tools/testing/selftests/kvm/include/test_util.h +++ b/tools/testing/selftests/kvm/include/test_util.h @@ -53,11 +53,11 @@ void test_assert(bool exp, const char *exp_str, #define TEST_ASSERT(e, fmt, ...) \ test_assert((e), #e, __FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define ASSERT_EQ(a, b) do { \ +#define TEST_ASSERT_EQ(a, b) do { \ typeof(a) __a = (a); \ typeof(b) __b = (b); \ TEST_ASSERT(__a == __b, \ - "ASSERT_EQ(%s, %s) failed.\n" \ + "TEST_ASSERT_EQ(%s, %s) failed.\n" \ "\t%s is %#lx\n" \ "\t%s is %#lx", \ #a, #b, #a, (unsigned long) __a, #b, (unsigned long) __b); \ diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 9741a7ff6380f..3170d7a4520be 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -994,7 +994,7 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, if (src_type == VM_MEM_SRC_ANONYMOUS_THP) alignment = max(backing_src_pagesz, alignment); - ASSERT_EQ(guest_paddr, align_up(guest_paddr, backing_src_pagesz)); + TEST_ASSERT_EQ(guest_paddr, align_up(guest_paddr, backing_src_pagesz)); /* Add enough memory to align up if necessary */ if (alignment > 1) diff --git a/tools/testing/selftests/kvm/max_guest_memory_test.c b/tools/testing/selftests/kvm/max_guest_memory_test.c index feaf2be20ff25..6628dc4dda89f 100644 --- a/tools/testing/selftests/kvm/max_guest_memory_test.c +++ b/tools/testing/selftests/kvm/max_guest_memory_test.c @@ -55,7 +55,7 @@ static void rendezvous_with_boss(void) static void run_vcpu(struct kvm_vcpu *vcpu) { vcpu_run(vcpu); - ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_DONE); + TEST_ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_DONE); } static void *vcpu_worker(void *data) diff --git a/tools/testing/selftests/kvm/s390x/cmma_test.c b/tools/testing/selftests/kvm/s390x/cmma_test.c index 1d73e78e8fa77..c8e0a6495a63a 100644 --- a/tools/testing/selftests/kvm/s390x/cmma_test.c +++ b/tools/testing/selftests/kvm/s390x/cmma_test.c @@ -237,8 +237,8 @@ static void test_get_cmma_basic(void) /* GET_CMMA_BITS without CMMA enabled should fail */ rc = vm_get_cmma_bits(vm, 0, &errno_out); - ASSERT_EQ(rc, -1); - ASSERT_EQ(errno_out, ENXIO); + TEST_ASSERT_EQ(rc, -1); + TEST_ASSERT_EQ(errno_out, ENXIO); enable_cmma(vm); vcpu = vm_vcpu_add(vm, 1, guest_do_one_essa); @@ -247,31 +247,31 @@ static void test_get_cmma_basic(void) /* GET_CMMA_BITS without migration mode and without peeking should fail */ rc = vm_get_cmma_bits(vm, 0, &errno_out); - ASSERT_EQ(rc, -1); - ASSERT_EQ(errno_out, EINVAL); + TEST_ASSERT_EQ(rc, -1); + TEST_ASSERT_EQ(errno_out, EINVAL); /* GET_CMMA_BITS without migration mode and with peeking should work */ rc = vm_get_cmma_bits(vm, KVM_S390_CMMA_PEEK, &errno_out); - ASSERT_EQ(rc, 0); - ASSERT_EQ(errno_out, 0); + TEST_ASSERT_EQ(rc, 0); + TEST_ASSERT_EQ(errno_out, 0); enable_dirty_tracking(vm); enable_migration_mode(vm); /* GET_CMMA_BITS with invalid flags */ rc = vm_get_cmma_bits(vm, 0xfeedc0fe, &errno_out); - ASSERT_EQ(rc, -1); - ASSERT_EQ(errno_out, EINVAL); + TEST_ASSERT_EQ(rc, -1); + TEST_ASSERT_EQ(errno_out, EINVAL); kvm_vm_free(vm); } static void assert_exit_was_hypercall(struct kvm_vcpu *vcpu) { - ASSERT_EQ(vcpu->run->exit_reason, 13); - ASSERT_EQ(vcpu->run->s390_sieic.icptcode, 4); - ASSERT_EQ(vcpu->run->s390_sieic.ipa, 0x8300); - ASSERT_EQ(vcpu->run->s390_sieic.ipb, 0x5010000); + TEST_ASSERT_EQ(vcpu->run->exit_reason, 13); + TEST_ASSERT_EQ(vcpu->run->s390_sieic.icptcode, 4); + TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipa, 0x8300); + TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipb, 0x5010000); } static void test_migration_mode(void) @@ -283,8 +283,8 @@ static void test_migration_mode(void) /* enabling migration mode on a VM without memory should fail */ rc = __enable_migration_mode(vm); - ASSERT_EQ(rc, -1); - ASSERT_EQ(errno, EINVAL); + TEST_ASSERT_EQ(rc, -1); + TEST_ASSERT_EQ(errno, EINVAL); TEST_ASSERT(!is_migration_mode_on(vm), "migration mode should still be off"); errno = 0; @@ -304,8 +304,8 @@ static void test_migration_mode(void) /* migration mode when memslots have dirty tracking off should fail */ rc = __enable_migration_mode(vm); - ASSERT_EQ(rc, -1); - ASSERT_EQ(errno, EINVAL); + TEST_ASSERT_EQ(rc, -1); + TEST_ASSERT_EQ(errno, EINVAL); TEST_ASSERT(!is_migration_mode_on(vm), "migration mode should still be off"); errno = 0; @@ -314,7 +314,7 @@ static void test_migration_mode(void) /* enabling migration mode should work now */ rc = __enable_migration_mode(vm); - ASSERT_EQ(rc, 0); + TEST_ASSERT_EQ(rc, 0); TEST_ASSERT(is_migration_mode_on(vm), "migration mode should be on"); errno = 0; @@ -350,7 +350,7 @@ static void test_migration_mode(void) */ vm_mem_region_set_flags(vm, TEST_DATA_TWO_MEMSLOT, KVM_MEM_LOG_DIRTY_PAGES); rc = __enable_migration_mode(vm); - ASSERT_EQ(rc, 0); + TEST_ASSERT_EQ(rc, 0); TEST_ASSERT(is_migration_mode_on(vm), "migration mode should be on"); errno = 0; @@ -394,9 +394,9 @@ static void assert_all_slots_cmma_dirty(struct kvm_vm *vm) }; memset(cmma_value_buf, 0xff, sizeof(cmma_value_buf)); vm_ioctl(vm, KVM_S390_GET_CMMA_BITS, &args); - ASSERT_EQ(args.count, MAIN_PAGE_COUNT); - ASSERT_EQ(args.remaining, TEST_DATA_PAGE_COUNT); - ASSERT_EQ(args.start_gfn, 0); + TEST_ASSERT_EQ(args.count, MAIN_PAGE_COUNT); + TEST_ASSERT_EQ(args.remaining, TEST_DATA_PAGE_COUNT); + TEST_ASSERT_EQ(args.start_gfn, 0); /* ...and then - after a hole - the TEST_DATA memslot should follow */ args = (struct kvm_s390_cmma_log){ @@ -407,9 +407,9 @@ static void assert_all_slots_cmma_dirty(struct kvm_vm *vm) }; memset(cmma_value_buf, 0xff, sizeof(cmma_value_buf)); vm_ioctl(vm, KVM_S390_GET_CMMA_BITS, &args); - ASSERT_EQ(args.count, TEST_DATA_PAGE_COUNT); - ASSERT_EQ(args.start_gfn, TEST_DATA_START_GFN); - ASSERT_EQ(args.remaining, 0); + TEST_ASSERT_EQ(args.count, TEST_DATA_PAGE_COUNT); + TEST_ASSERT_EQ(args.start_gfn, TEST_DATA_START_GFN); + TEST_ASSERT_EQ(args.remaining, 0); /* ...and nothing else should be there */ args = (struct kvm_s390_cmma_log){ @@ -420,9 +420,9 @@ static void assert_all_slots_cmma_dirty(struct kvm_vm *vm) }; memset(cmma_value_buf, 0xff, sizeof(cmma_value_buf)); vm_ioctl(vm, KVM_S390_GET_CMMA_BITS, &args); - ASSERT_EQ(args.count, 0); - ASSERT_EQ(args.start_gfn, 0); - ASSERT_EQ(args.remaining, 0); + TEST_ASSERT_EQ(args.count, 0); + TEST_ASSERT_EQ(args.start_gfn, 0); + TEST_ASSERT_EQ(args.remaining, 0); } /** @@ -498,11 +498,11 @@ static void assert_cmma_dirty(u64 first_dirty_gfn, u64 dirty_gfn_count, const struct kvm_s390_cmma_log *res) { - ASSERT_EQ(res->start_gfn, first_dirty_gfn); - ASSERT_EQ(res->count, dirty_gfn_count); + TEST_ASSERT_EQ(res->start_gfn, first_dirty_gfn); + TEST_ASSERT_EQ(res->count, dirty_gfn_count); for (size_t i = 0; i < dirty_gfn_count; i++) - ASSERT_EQ(cmma_value_buf[0], 0x0); /* stable state */ - ASSERT_EQ(cmma_value_buf[dirty_gfn_count], 0xff); /* not touched */ + TEST_ASSERT_EQ(cmma_value_buf[0], 0x0); /* stable state */ + TEST_ASSERT_EQ(cmma_value_buf[dirty_gfn_count], 0xff); /* not touched */ } static void test_get_skip_holes(void) diff --git a/tools/testing/selftests/kvm/s390x/memop.c b/tools/testing/selftests/kvm/s390x/memop.c index 8e4b94d7b8dd9..de73dc0309051 100644 --- a/tools/testing/selftests/kvm/s390x/memop.c +++ b/tools/testing/selftests/kvm/s390x/memop.c @@ -281,8 +281,8 @@ enum stage { if (uc.cmd == UCALL_ABORT) { \ REPORT_GUEST_ASSERT_2(uc, "hints: %lu, %lu"); \ } \ - ASSERT_EQ(uc.cmd, UCALL_SYNC); \ - ASSERT_EQ(uc.args[1], __stage); \ + TEST_ASSERT_EQ(uc.cmd, UCALL_SYNC); \ + TEST_ASSERT_EQ(uc.args[1], __stage); \ }) \ static void prepare_mem12(void) @@ -808,7 +808,7 @@ static void test_termination(void) HOST_SYNC(t.vcpu, STAGE_IDLED); MOP(t.vm, ABSOLUTE, READ, &teid, sizeof(teid), GADDR(prefix + 168)); /* Bits 56, 60, 61 form a code, 0 being the only one allowing for termination */ - ASSERT_EQ(teid & teid_mask, 0); + TEST_ASSERT_EQ(teid & teid_mask, 0); kvm_vm_free(t.kvm_vm); } diff --git a/tools/testing/selftests/kvm/s390x/tprot.c b/tools/testing/selftests/kvm/s390x/tprot.c index a9a0b76e5fa45..40d3ea16c052f 100644 --- a/tools/testing/selftests/kvm/s390x/tprot.c +++ b/tools/testing/selftests/kvm/s390x/tprot.c @@ -191,8 +191,8 @@ static void guest_code(void) get_ucall(__vcpu, &uc); \ if (uc.cmd == UCALL_ABORT) \ REPORT_GUEST_ASSERT_2(uc, "hints: %lu, %lu"); \ - ASSERT_EQ(uc.cmd, UCALL_SYNC); \ - ASSERT_EQ(uc.args[1], __stage); \ + TEST_ASSERT_EQ(uc.cmd, UCALL_SYNC); \ + TEST_ASSERT_EQ(uc.args[1], __stage); \ }) #define HOST_SYNC(vcpu, stage) \ diff --git a/tools/testing/selftests/kvm/x86_64/dirty_log_page_splitting_test.c b/tools/testing/selftests/kvm/x86_64/dirty_log_page_splitting_test.c index beb7e2c102113..634c6bfcd5720 100644 --- a/tools/testing/selftests/kvm/x86_64/dirty_log_page_splitting_test.c +++ b/tools/testing/selftests/kvm/x86_64/dirty_log_page_splitting_test.c @@ -72,7 +72,7 @@ static void vcpu_worker(struct memstress_vcpu_args *vcpu_args) vcpu_run(vcpu); - ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_SYNC); + TEST_ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_SYNC); vcpu_last_completed_iteration[vcpu_idx] = current_iteration; @@ -179,12 +179,12 @@ static void run_test(enum vm_guest_mode mode, void *unused) * with that capability. */ if (dirty_log_manual_caps) { - ASSERT_EQ(stats_clear_pass[0].hugepages, 0); - ASSERT_EQ(stats_clear_pass[0].pages_4k, total_4k_pages); - ASSERT_EQ(stats_dirty_logging_enabled.hugepages, stats_populated.hugepages); + TEST_ASSERT_EQ(stats_clear_pass[0].hugepages, 0); + TEST_ASSERT_EQ(stats_clear_pass[0].pages_4k, total_4k_pages); + TEST_ASSERT_EQ(stats_dirty_logging_enabled.hugepages, stats_populated.hugepages); } else { - ASSERT_EQ(stats_dirty_logging_enabled.hugepages, 0); - ASSERT_EQ(stats_dirty_logging_enabled.pages_4k, total_4k_pages); + TEST_ASSERT_EQ(stats_dirty_logging_enabled.hugepages, 0); + TEST_ASSERT_EQ(stats_dirty_logging_enabled.pages_4k, total_4k_pages); } /* @@ -192,9 +192,9 @@ static void run_test(enum vm_guest_mode mode, void *unused) * memory again, the page counts should be the same as they were * right after initial population of memory. */ - ASSERT_EQ(stats_populated.pages_4k, stats_repopulated.pages_4k); - ASSERT_EQ(stats_populated.pages_2m, stats_repopulated.pages_2m); - ASSERT_EQ(stats_populated.pages_1g, stats_repopulated.pages_1g); + TEST_ASSERT_EQ(stats_populated.pages_4k, stats_repopulated.pages_4k); + TEST_ASSERT_EQ(stats_populated.pages_2m, stats_repopulated.pages_2m); + TEST_ASSERT_EQ(stats_populated.pages_1g, stats_repopulated.pages_1g); } static void help(char *name) diff --git a/tools/testing/selftests/kvm/x86_64/exit_on_emulation_failure_test.c b/tools/testing/selftests/kvm/x86_64/exit_on_emulation_failure_test.c index e334844d6e1d7..6c2e5e0ceb1f7 100644 --- a/tools/testing/selftests/kvm/x86_64/exit_on_emulation_failure_test.c +++ b/tools/testing/selftests/kvm/x86_64/exit_on_emulation_failure_test.c @@ -35,7 +35,7 @@ int main(int argc, char *argv[]) vcpu_run(vcpu); handle_flds_emulation_failure_exit(vcpu); vcpu_run(vcpu); - ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_DONE); + TEST_ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_DONE); kvm_vm_free(vm); return 0; diff --git a/tools/testing/selftests/kvm/x86_64/nested_exceptions_test.c b/tools/testing/selftests/kvm/x86_64/nested_exceptions_test.c index 6502aa23c2f84..5f074a6da90cd 100644 --- a/tools/testing/selftests/kvm/x86_64/nested_exceptions_test.c +++ b/tools/testing/selftests/kvm/x86_64/nested_exceptions_test.c @@ -247,12 +247,12 @@ int main(int argc, char *argv[]) /* Verify the pending events comes back out the same as it went in. */ vcpu_events_get(vcpu, &events); - ASSERT_EQ(events.flags & KVM_VCPUEVENT_VALID_PAYLOAD, - KVM_VCPUEVENT_VALID_PAYLOAD); - ASSERT_EQ(events.exception.pending, true); - ASSERT_EQ(events.exception.nr, SS_VECTOR); - ASSERT_EQ(events.exception.has_error_code, true); - ASSERT_EQ(events.exception.error_code, SS_ERROR_CODE); + TEST_ASSERT_EQ(events.flags & KVM_VCPUEVENT_VALID_PAYLOAD, + KVM_VCPUEVENT_VALID_PAYLOAD); + TEST_ASSERT_EQ(events.exception.pending, true); + TEST_ASSERT_EQ(events.exception.nr, SS_VECTOR); + TEST_ASSERT_EQ(events.exception.has_error_code, true); + TEST_ASSERT_EQ(events.exception.error_code, SS_ERROR_CODE); /* * Run for real with the pending #SS, L1 should get a VM-Exit due to diff --git a/tools/testing/selftests/kvm/x86_64/recalc_apic_map_test.c b/tools/testing/selftests/kvm/x86_64/recalc_apic_map_test.c index 4c416ebe7d66d..cbc92a862ea9c 100644 --- a/tools/testing/selftests/kvm/x86_64/recalc_apic_map_test.c +++ b/tools/testing/selftests/kvm/x86_64/recalc_apic_map_test.c @@ -57,7 +57,7 @@ int main(void) for (i = 0; i < KVM_MAX_VCPUS; i++) vcpu_set_msr(vcpus[i], MSR_IA32_APICBASE, LAPIC_X2APIC); - ASSERT_EQ(pthread_create(&thread, NULL, race, vcpus[0]), 0); + TEST_ASSERT_EQ(pthread_create(&thread, NULL, race, vcpus[0]), 0); vcpuN = vcpus[KVM_MAX_VCPUS - 1]; for (t = time(NULL) + TIMEOUT; time(NULL) < t;) { @@ -65,8 +65,8 @@ int main(void) vcpu_set_msr(vcpuN, MSR_IA32_APICBASE, LAPIC_DISABLED); } - ASSERT_EQ(pthread_cancel(thread), 0); - ASSERT_EQ(pthread_join(thread, NULL), 0); + TEST_ASSERT_EQ(pthread_cancel(thread), 0); + TEST_ASSERT_EQ(pthread_join(thread, NULL), 0); kvm_vm_free(vm); diff --git a/tools/testing/selftests/kvm/x86_64/sync_regs_test.c b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c index 7e5b13869e2e7..93fac74ca0a7b 100644 --- a/tools/testing/selftests/kvm/x86_64/sync_regs_test.c +++ b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c @@ -176,7 +176,7 @@ static void race_sync_regs(void *racer) !!(run->s.regs.sregs.cr4 & X86_CR4_PAE), !!(run->s.regs.sregs.efer & EFER_LME)); - ASSERT_EQ(pthread_create(&thread, NULL, racer, (void *)run), 0); + TEST_ASSERT_EQ(pthread_create(&thread, NULL, racer, (void *)run), 0); for (t = time(NULL) + TIMEOUT; time(NULL) < t;) { __vcpu_run(vcpu); @@ -187,8 +187,8 @@ static void race_sync_regs(void *racer) } } - ASSERT_EQ(pthread_cancel(thread), 0); - ASSERT_EQ(pthread_join(thread, NULL), 0); + TEST_ASSERT_EQ(pthread_cancel(thread), 0); + TEST_ASSERT_EQ(pthread_join(thread, NULL), 0); kvm_vm_free(vm); } diff --git a/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c b/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c index c9f67702f657f..9265965bd2cd3 100644 --- a/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c +++ b/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c @@ -103,39 +103,39 @@ int main(void) vm = vm_create_with_one_vcpu(&vcpu, guest_code); val = 0; - ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), val); - ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); + TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), val); + TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); /* Guest: writes to MSR_IA32_TSC affect both MSRs. */ run_vcpu(vcpu, 1); val = 1ull * GUEST_STEP; - ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), val); - ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); + TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), val); + TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); /* Guest: writes to MSR_IA32_TSC_ADJUST affect both MSRs. */ run_vcpu(vcpu, 2); val = 2ull * GUEST_STEP; - ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), val); - ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); + TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), val); + TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); /* * Host: writes to MSR_IA32_TSC set the host-side offset * and therefore do not change MSR_IA32_TSC_ADJUST. */ vcpu_set_msr(vcpu, MSR_IA32_TSC, HOST_ADJUST + val); - ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), HOST_ADJUST + val); - ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); + TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), HOST_ADJUST + val); + TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); run_vcpu(vcpu, 3); /* Host: writes to MSR_IA32_TSC_ADJUST do not modify the TSC. */ vcpu_set_msr(vcpu, MSR_IA32_TSC_ADJUST, UNITY * 123456); - ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), HOST_ADJUST + val); - ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_TSC_ADJUST), UNITY * 123456); + TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), HOST_ADJUST + val); + TEST_ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_TSC_ADJUST), UNITY * 123456); /* Restore previous value. */ vcpu_set_msr(vcpu, MSR_IA32_TSC_ADJUST, val); - ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), HOST_ADJUST + val); - ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); + TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), HOST_ADJUST + val); + TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); /* * Guest: writes to MSR_IA32_TSC_ADJUST do not destroy the @@ -143,8 +143,8 @@ int main(void) */ run_vcpu(vcpu, 4); val = 3ull * GUEST_STEP; - ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), HOST_ADJUST + val); - ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); + TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), HOST_ADJUST + val); + TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); /* * Guest: writes to MSR_IA32_TSC affect both MSRs, so the host-side @@ -152,8 +152,8 @@ int main(void) */ run_vcpu(vcpu, 5); val = 4ull * GUEST_STEP; - ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), val); - ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val - HOST_ADJUST); + TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), val); + TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val - HOST_ADJUST); kvm_vm_free(vm); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c b/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c index be0bdb8c6f78c..a9b827c69f32c 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c @@ -50,7 +50,7 @@ static void set_timer(void) timer.it_value.tv_sec = 0; timer.it_value.tv_usec = 200; timer.it_interval = timer.it_value; - ASSERT_EQ(setitimer(ITIMER_REAL, &timer, NULL), 0); + TEST_ASSERT_EQ(setitimer(ITIMER_REAL, &timer, NULL), 0); } static void set_or_clear_invalid_guest_state(struct kvm_vcpu *vcpu, bool set) diff --git a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c index 4c90f76930f99..34efd57c2b32f 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c @@ -103,7 +103,8 @@ static void test_guest_wrmsr_perf_capabilities(union perf_capabilities host_cap) TEST_FAIL("Unexpected ucall: %lu", uc.cmd); } - ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), host_cap.capabilities); + TEST_ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), + host_cap.capabilities); vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities); diff --git a/tools/testing/selftests/kvm/x86_64/xapic_state_test.c b/tools/testing/selftests/kvm/x86_64/xapic_state_test.c index 396c13f42457d..ab75b873a4ad8 100644 --- a/tools/testing/selftests/kvm/x86_64/xapic_state_test.c +++ b/tools/testing/selftests/kvm/x86_64/xapic_state_test.c @@ -65,17 +65,17 @@ static void ____test_icr(struct xapic_vcpu *x, uint64_t val) vcpu_ioctl(vcpu, KVM_SET_LAPIC, &xapic); vcpu_run(vcpu); - ASSERT_EQ(get_ucall(vcpu, &uc), UCALL_SYNC); - ASSERT_EQ(uc.args[1], val); + TEST_ASSERT_EQ(get_ucall(vcpu, &uc), UCALL_SYNC); + TEST_ASSERT_EQ(uc.args[1], val); vcpu_ioctl(vcpu, KVM_GET_LAPIC, &xapic); icr = (u64)(*((u32 *)&xapic.regs[APIC_ICR])) | (u64)(*((u32 *)&xapic.regs[APIC_ICR2])) << 32; if (!x->is_x2apic) { val &= (-1u | (0xffull << (32 + 24))); - ASSERT_EQ(icr, val & ~APIC_ICR_BUSY); + TEST_ASSERT_EQ(icr, val & ~APIC_ICR_BUSY); } else { - ASSERT_EQ(icr & ~APIC_ICR_BUSY, val & ~APIC_ICR_BUSY); + TEST_ASSERT_EQ(icr & ~APIC_ICR_BUSY, val & ~APIC_ICR_BUSY); } } diff --git a/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c b/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c index c94cde3b523f2..e149d0574961c 100644 --- a/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c +++ b/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c @@ -108,16 +108,16 @@ int main(int argc, char *argv[]) vcpu_run(vcpu); if (run->exit_reason == KVM_EXIT_XEN) { - ASSERT_EQ(run->xen.type, KVM_EXIT_XEN_HCALL); - ASSERT_EQ(run->xen.u.hcall.cpl, 0); - ASSERT_EQ(run->xen.u.hcall.longmode, 1); - ASSERT_EQ(run->xen.u.hcall.input, INPUTVALUE); - ASSERT_EQ(run->xen.u.hcall.params[0], ARGVALUE(1)); - ASSERT_EQ(run->xen.u.hcall.params[1], ARGVALUE(2)); - ASSERT_EQ(run->xen.u.hcall.params[2], ARGVALUE(3)); - ASSERT_EQ(run->xen.u.hcall.params[3], ARGVALUE(4)); - ASSERT_EQ(run->xen.u.hcall.params[4], ARGVALUE(5)); - ASSERT_EQ(run->xen.u.hcall.params[5], ARGVALUE(6)); + TEST_ASSERT_EQ(run->xen.type, KVM_EXIT_XEN_HCALL); + TEST_ASSERT_EQ(run->xen.u.hcall.cpl, 0); + TEST_ASSERT_EQ(run->xen.u.hcall.longmode, 1); + TEST_ASSERT_EQ(run->xen.u.hcall.input, INPUTVALUE); + TEST_ASSERT_EQ(run->xen.u.hcall.params[0], ARGVALUE(1)); + TEST_ASSERT_EQ(run->xen.u.hcall.params[1], ARGVALUE(2)); + TEST_ASSERT_EQ(run->xen.u.hcall.params[2], ARGVALUE(3)); + TEST_ASSERT_EQ(run->xen.u.hcall.params[3], ARGVALUE(4)); + TEST_ASSERT_EQ(run->xen.u.hcall.params[4], ARGVALUE(5)); + TEST_ASSERT_EQ(run->xen.u.hcall.params[5], ARGVALUE(6)); run->xen.u.hcall.result = RETVALUE; continue; } -- GitLab From b145c58d95fff280c2726d0024005ae0a4ec378d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:11 -0700 Subject: [PATCH 0698/3445] KVM: selftests: Make TEST_ASSERT_EQ() output look like normal TEST_ASSERT() Clean up TEST_ASSERT_EQ() so that the (mostly) raw code is captured in the main assert message, not the helper macro's code. E.g. make this: x86_64/tsc_msrs_test.c:106: __a == __b pid=40470 tid=40470 errno=0 - Success 1 0x000000000040170e: main at tsc_msrs_test.c:106 2 0x0000000000416f23: __libc_start_call_main at libc-start.o:? 3 0x000000000041856f: __libc_start_main_impl at ??:? 4 0x0000000000401ef0: _start at ??:? TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), val + 1) failed. rounded_host_rdmsr(MSR_IA32_TSC) is 0 val + 1 is 0x1 look like this: x86_64/tsc_msrs_test.c:106: rounded_host_rdmsr(MSR_IA32_TSC) == val + 1 pid=5737 tid=5737 errno=0 - Success 1 0x0000000000401714: main at tsc_msrs_test.c:106 2 0x0000000000415c23: __libc_start_call_main at libc-start.o:? 3 0x000000000041726f: __libc_start_main_impl at ??:? 4 0x0000000000401e60: _start at ??:? 0 != 0x1 (rounded_host_rdmsr(MSR_IA32_TSC) != val + 1) Opportunstically clean up the formatting of the entire macro. Link: https://lore.kernel.org/r/20230729003643.1053367-3-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/include/test_util.h | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h index e734e52d8a3a6..a4bea44f990ce 100644 --- a/tools/testing/selftests/kvm/include/test_util.h +++ b/tools/testing/selftests/kvm/include/test_util.h @@ -53,14 +53,13 @@ void test_assert(bool exp, const char *exp_str, #define TEST_ASSERT(e, fmt, ...) \ test_assert((e), #e, __FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define TEST_ASSERT_EQ(a, b) do { \ - typeof(a) __a = (a); \ - typeof(b) __b = (b); \ - TEST_ASSERT(__a == __b, \ - "TEST_ASSERT_EQ(%s, %s) failed.\n" \ - "\t%s is %#lx\n" \ - "\t%s is %#lx", \ - #a, #b, #a, (unsigned long) __a, #b, (unsigned long) __b); \ +#define TEST_ASSERT_EQ(a, b) \ +do { \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + test_assert(__a == __b, #a " == " #b, __FILE__, __LINE__, \ + "%#lx != %#lx (%s != %s)", \ + (unsigned long)(__a), (unsigned long)(__b), #a, #b);\ } while (0) #define TEST_ASSERT_KVM_EXIT_REASON(vcpu, expected) do { \ -- GitLab From 6783ca4105a75d1ba4f89b13cef1bc1f677c41e5 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:12 -0700 Subject: [PATCH 0699/3445] KVM: selftests: Add a shameful hack to preserve/clobber GPRs across ucall Preserve or clobber all GPRs (except RIP and RSP, as they're saved and restored via the VMCS) when performing a ucall on x86 to fudge around a horrific long-standing bug in selftests' nested VMX support where L2's GPRs are not preserved across a nested VM-Exit. I.e. if a test triggers a nested VM-Exit to L1 in response to a ucall, e.g. GUEST_SYNC(), then L2's GPR state can be corrupted. The issues manifests as an unexpected #GP in clear_bit() when running the hyperv_evmcs test due to RBX being used to track the ucall object, and RBX being clobbered by the nested VM-Exit. The problematic hyperv_evmcs testcase is where L0 (test's host userspace) injects an NMI in response to GUEST_SYNC(8) from L2, but the bug could "randomly" manifest in any test that induces a nested VM-Exit from L0. The bug hasn't caused failures in the past due to sheer dumb luck. The obvious fix is to rework the nVMX helpers to save/restore L2 GPRs across VM-Exit and VM-Enter, but that is a much bigger task and carries its own risks, e.g. nSVM does save/restore GPRs, but not in a thread-safe manner, and there is a _lot_ of cleanup that can be done to unify code for doing VM-Enter on nVMX, nSVM, and eVMCS. Link: https://lore.kernel.org/r/20230729003643.1053367-4-seanjc@google.com Signed-off-by: Sean Christopherson --- .../testing/selftests/kvm/lib/x86_64/ucall.c | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/x86_64/ucall.c b/tools/testing/selftests/kvm/lib/x86_64/ucall.c index 4d41dc63cc9ed..a53df3ece2f8b 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/ucall.c +++ b/tools/testing/selftests/kvm/lib/x86_64/ucall.c @@ -14,8 +14,36 @@ void ucall_arch_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa) void ucall_arch_do_ucall(vm_vaddr_t uc) { - asm volatile("in %[port], %%al" - : : [port] "d" (UCALL_PIO_PORT), "D" (uc) : "rax", "memory"); + /* + * FIXME: Revert this hack (the entire commit that added it) once nVMX + * preserves L2 GPRs across a nested VM-Exit. If a ucall from L2, e.g. + * to do a GUEST_SYNC(), lands the vCPU in L1, any and all GPRs can be + * clobbered by L1. Save and restore non-volatile GPRs (clobbering RBP + * in particular is problematic) along with RDX and RDI (which are + * inputs), and clobber volatile GPRs. *sigh* + */ +#define HORRIFIC_L2_UCALL_CLOBBER_HACK \ + "rcx", "rsi", "r8", "r9", "r10", "r11" + + asm volatile("push %%rbp\n\t" + "push %%r15\n\t" + "push %%r14\n\t" + "push %%r13\n\t" + "push %%r12\n\t" + "push %%rbx\n\t" + "push %%rdx\n\t" + "push %%rdi\n\t" + "in %[port], %%al\n\t" + "pop %%rdi\n\t" + "pop %%rdx\n\t" + "pop %%rbx\n\t" + "pop %%r12\n\t" + "pop %%r13\n\t" + "pop %%r14\n\t" + "pop %%r15\n\t" + "pop %%rbp\n\t" + : : [port] "d" (UCALL_PIO_PORT), "D" (uc) : "rax", "memory", + HORRIFIC_L2_UCALL_CLOBBER_HACK); } void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu) -- GitLab From a1c1b55e116c14de4f8a78286b502101f2a1620c Mon Sep 17 00:00:00 2001 From: Aaron Lewis Date: Fri, 28 Jul 2023 17:36:13 -0700 Subject: [PATCH 0700/3445] KVM: selftests: Add strnlen() to the string overrides Add strnlen() to the string overrides to allow it to be called in the guest. The implementation for strnlen() was taken from the kernel's generic version, lib/string.c. This will be needed when printf() is introduced. Signed-off-by: Aaron Lewis Link: https://lore.kernel.org/r/20230729003643.1053367-5-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/Makefile | 1 + tools/testing/selftests/kvm/lib/string_override.c | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index c692cc86e7da8..f6c14ab476ac3 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -204,6 +204,7 @@ endif CFLAGS += -Wall -Wstrict-prototypes -Wuninitialized -O2 -g -std=gnu99 \ -Wno-gnu-variable-sized-type-not-at-end -MD\ -fno-builtin-memcmp -fno-builtin-memcpy -fno-builtin-memset \ + -fno-builtin-strnlen \ -fno-stack-protector -fno-PIE -I$(LINUX_TOOL_INCLUDE) \ -I$(LINUX_TOOL_ARCH_INCLUDE) -I$(LINUX_HDR_PATH) -Iinclude \ -I$( Date: Fri, 28 Jul 2023 17:36:14 -0700 Subject: [PATCH 0701/3445] KVM: selftests: Add guest_snprintf() to KVM selftests Add a local version of guest_snprintf() for use in the guest. Having a local copy allows the guest access to string formatting options without dependencies on LIBC. LIBC is problematic because it heavily relies on both AVX-512 instructions and a TLS, neither of which are guaranteed to be set up in the guest. The file guest_sprintf.c was lifted from arch/x86/boot/printf.c and adapted to work in the guest, including the addition of buffer length. I.e. s/sprintf/snprintf/ The functions where prefixed with "guest_" to allow guests to explicitly call them. A string formatted by this function is expected to succeed or die. If something goes wrong during the formatting process a GUEST_ASSERT() will be thrown. Signed-off-by: Aaron Lewis Link: https://lore.kernel.org/all/mtdi6smhur5rqffvpu7qux7mptonw223y2653x2nwzvgm72nlo@zyc4w3kwl3rg [sean: add a link to the discussion of other options] Link: https://lore.kernel.org/r/20230729003643.1053367-6-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/Makefile | 1 + .../testing/selftests/kvm/include/test_util.h | 3 + .../testing/selftests/kvm/lib/guest_sprintf.c | 307 ++++++++++++++++++ 3 files changed, 311 insertions(+) create mode 100644 tools/testing/selftests/kvm/lib/guest_sprintf.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index f6c14ab476ac3..f65889f5a0836 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -23,6 +23,7 @@ LIBKVM += lib/guest_modes.c LIBKVM += lib/io.c LIBKVM += lib/kvm_util.c LIBKVM += lib/memstress.c +LIBKVM += lib/guest_sprintf.c LIBKVM += lib/rbtree.c LIBKVM += lib/sparsebit.c LIBKVM += lib/test_util.c diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h index a4bea44f990ce..7a5907da17197 100644 --- a/tools/testing/selftests/kvm/include/test_util.h +++ b/tools/testing/selftests/kvm/include/test_util.h @@ -185,4 +185,7 @@ static inline uint32_t atoi_non_negative(const char *name, const char *num_str) return num; } +int guest_vsnprintf(char *buf, int n, const char *fmt, va_list args); +int guest_snprintf(char *buf, int n, const char *fmt, ...); + #endif /* SELFTEST_KVM_TEST_UTIL_H */ diff --git a/tools/testing/selftests/kvm/lib/guest_sprintf.c b/tools/testing/selftests/kvm/lib/guest_sprintf.c new file mode 100644 index 0000000000000..c4a69d8aeb68c --- /dev/null +++ b/tools/testing/selftests/kvm/lib/guest_sprintf.c @@ -0,0 +1,307 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include "test_util.h" +#include "kvm_util.h" +#include "ucall_common.h" + +#define APPEND_BUFFER_SAFE(str, end, v) \ +do { \ + GUEST_ASSERT(str < end); \ + *str++ = (v); \ +} while (0) + +static int isdigit(int ch) +{ + return (ch >= '0') && (ch <= '9'); +} + +static int skip_atoi(const char **s) +{ + int i = 0; + + while (isdigit(**s)) + i = i * 10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SMALL 32 /* Must be 32 == 0x20 */ +#define SPECIAL 64 /* 0x */ + +#define __do_div(n, base) \ +({ \ + int __res; \ + \ + __res = ((uint64_t) n) % (uint32_t) base; \ + n = ((uint64_t) n) / (uint32_t) base; \ + __res; \ +}) + +static char *number(char *str, const char *end, long num, int base, int size, + int precision, int type) +{ + /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ + static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ + + char tmp[66]; + char c, sign, locase; + int i; + + /* + * locase = 0 or 0x20. ORing digits or letters with 'locase' + * produces same digits or (maybe lowercased) letters + */ + locase = (type & SMALL); + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 16) + return NULL; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++] = '0'; + else + while (num != 0) + tmp[i++] = (digits[__do_div(num, base)] | locase); + if (i > precision) + precision = i; + size -= precision; + if (!(type & (ZEROPAD + LEFT))) + while (size-- > 0) + APPEND_BUFFER_SAFE(str, end, ' '); + if (sign) + APPEND_BUFFER_SAFE(str, end, sign); + if (type & SPECIAL) { + if (base == 8) + APPEND_BUFFER_SAFE(str, end, '0'); + else if (base == 16) { + APPEND_BUFFER_SAFE(str, end, '0'); + APPEND_BUFFER_SAFE(str, end, 'x'); + } + } + if (!(type & LEFT)) + while (size-- > 0) + APPEND_BUFFER_SAFE(str, end, c); + while (i < precision--) + APPEND_BUFFER_SAFE(str, end, '0'); + while (i-- > 0) + APPEND_BUFFER_SAFE(str, end, tmp[i]); + while (size-- > 0) + APPEND_BUFFER_SAFE(str, end, ' '); + + return str; +} + +int guest_vsnprintf(char *buf, int n, const char *fmt, va_list args) +{ + char *str, *end; + const char *s; + uint64_t num; + int i, base; + int len; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* + * min. # of digits for integers; max + * number of chars for from string + */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + end = buf + n; + GUEST_ASSERT(buf < end); + GUEST_ASSERT(n > 0); + + for (str = buf; *fmt; ++fmt) { + if (*fmt != '%') { + APPEND_BUFFER_SAFE(str, end, *fmt); + continue; + } + + /* process flags */ + flags = 0; +repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': + flags |= LEFT; + goto repeat; + case '+': + flags |= PLUS; + goto repeat; + case ' ': + flags |= SPACE; + goto repeat; + case '#': + flags |= SPECIAL; + goto repeat; + case '0': + flags |= ZEROPAD; + goto repeat; + } + + /* get field width */ + field_width = -1; + if (isdigit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (isdigit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + APPEND_BUFFER_SAFE(str, end, ' '); + APPEND_BUFFER_SAFE(str, end, + (uint8_t)va_arg(args, int)); + while (--field_width > 0) + APPEND_BUFFER_SAFE(str, end, ' '); + continue; + + case 's': + s = va_arg(args, char *); + len = strnlen(s, precision); + + if (!(flags & LEFT)) + while (len < field_width--) + APPEND_BUFFER_SAFE(str, end, ' '); + for (i = 0; i < len; ++i) + APPEND_BUFFER_SAFE(str, end, *s++); + while (len < field_width--) + APPEND_BUFFER_SAFE(str, end, ' '); + continue; + + case 'p': + if (field_width == -1) { + field_width = 2 * sizeof(void *); + flags |= SPECIAL | SMALL | ZEROPAD; + } + str = number(str, end, + (uint64_t)va_arg(args, void *), 16, + field_width, precision, flags); + continue; + + case 'n': + if (qualifier == 'l') { + long *ip = va_arg(args, long *); + *ip = (str - buf); + } else { + int *ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + APPEND_BUFFER_SAFE(str, end, '%'); + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'x': + flags |= SMALL; + case 'X': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + APPEND_BUFFER_SAFE(str, end, '%'); + if (*fmt) + APPEND_BUFFER_SAFE(str, end, *fmt); + else + --fmt; + continue; + } + if (qualifier == 'l') + num = va_arg(args, uint64_t); + else if (qualifier == 'h') { + num = (uint16_t)va_arg(args, int); + if (flags & SIGN) + num = (int16_t)num; + } else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, uint32_t); + str = number(str, end, num, base, field_width, precision, flags); + } + + GUEST_ASSERT(str < end); + *str = '\0'; + return str - buf; +} + +int guest_snprintf(char *buf, int n, const char *fmt, ...) +{ + va_list va; + int len; + + va_start(va, fmt); + len = guest_vsnprintf(buf, n, fmt, va); + va_end(va); + + return len; +} -- GitLab From 215a681710a554b224d743e4a9cd68965889713c Mon Sep 17 00:00:00 2001 From: Aaron Lewis Date: Fri, 28 Jul 2023 17:36:15 -0700 Subject: [PATCH 0702/3445] KVM: selftests: Add additional pages to the guest to accommodate ucall Add additional pages to the guest to account for the number of pages the ucall headers need. The only reason things worked before is the ucall headers are fairly small. If they were ever to increase in size the guest could run out of memory. This is done in preparation for adding string formatting options to the guest through the ucall framework which increases the size of the ucall headers. Fixes: 426729b2cf2e ("KVM: selftests: Add ucall pool based implementation") Signed-off-by: Aaron Lewis Link: https://lore.kernel.org/r/20230729003643.1053367-7-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/include/ucall_common.h | 1 + tools/testing/selftests/kvm/lib/kvm_util.c | 4 ++++ tools/testing/selftests/kvm/lib/ucall_common.c | 5 +++++ 3 files changed, 10 insertions(+) diff --git a/tools/testing/selftests/kvm/include/ucall_common.h b/tools/testing/selftests/kvm/include/ucall_common.h index 1a6aaef5ccae1..bcbb362aa77fa 100644 --- a/tools/testing/selftests/kvm/include/ucall_common.h +++ b/tools/testing/selftests/kvm/include/ucall_common.h @@ -34,6 +34,7 @@ void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu); void ucall(uint64_t cmd, int nargs, ...); uint64_t get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc); void ucall_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa); +int ucall_nr_pages_required(uint64_t page_size); /* * Perform userspace call without any associated data. This bare call avoids diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 3170d7a4520be..7a8af1821f5da 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -312,6 +312,7 @@ static uint64_t vm_nr_pages_required(enum vm_guest_mode mode, uint32_t nr_runnable_vcpus, uint64_t extra_mem_pages) { + uint64_t page_size = vm_guest_mode_params[mode].page_size; uint64_t nr_pages; TEST_ASSERT(nr_runnable_vcpus, @@ -340,6 +341,9 @@ static uint64_t vm_nr_pages_required(enum vm_guest_mode mode, */ nr_pages += (nr_pages + extra_mem_pages) / PTES_PER_MIN_PAGE * 2; + /* Account for the number of pages needed by ucall. */ + nr_pages += ucall_nr_pages_required(page_size); + return vm_adjust_num_guest_pages(mode, nr_pages); } diff --git a/tools/testing/selftests/kvm/lib/ucall_common.c b/tools/testing/selftests/kvm/lib/ucall_common.c index 2f0e2ea941cc6..77ada362273d7 100644 --- a/tools/testing/selftests/kvm/lib/ucall_common.c +++ b/tools/testing/selftests/kvm/lib/ucall_common.c @@ -11,6 +11,11 @@ struct ucall_header { struct ucall ucalls[KVM_MAX_VCPUS]; }; +int ucall_nr_pages_required(uint64_t page_size) +{ + return align_up(sizeof(struct ucall_header), page_size) / page_size; +} + /* * ucall_pool holds per-VM values (global data is duplicated by each VM), it * must not be accessed from host code. -- GitLab From 57e5c1fef5ecc7c346ff971817ba6985643e0a24 Mon Sep 17 00:00:00 2001 From: Aaron Lewis Date: Fri, 28 Jul 2023 17:36:16 -0700 Subject: [PATCH 0703/3445] KVM: selftests: Add string formatting options to ucall Add more flexibility to guest debugging and testing by adding GUEST_PRINTF() and GUEST_ASSERT_FMT() to the ucall framework. Add a sized buffer to the ucall structure to hold the formatted string, i.e. to allow the guest to easily resolve the string, and thus avoid the ugly pattern of the host side having to make assumptions about the desired format, as well as having to pass around a large number of parameters. The buffer size was chosen to accommodate most use cases, and based on similar usage. E.g. printf() uses the same size buffer in arch/x86/boot/printf.c. And 1KiB ought to be enough for anybody. Signed-off-by: Aaron Lewis [sean: massage changelog, wrap macro param in ()] Link: https://lore.kernel.org/r/20230729003643.1053367-8-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/include/ucall_common.h | 7 +++++++ tools/testing/selftests/kvm/lib/ucall_common.c | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/tools/testing/selftests/kvm/include/ucall_common.h b/tools/testing/selftests/kvm/include/ucall_common.h index bcbb362aa77fa..b5548aeba9f0c 100644 --- a/tools/testing/selftests/kvm/include/ucall_common.h +++ b/tools/testing/selftests/kvm/include/ucall_common.h @@ -13,15 +13,18 @@ enum { UCALL_NONE, UCALL_SYNC, UCALL_ABORT, + UCALL_PRINTF, UCALL_DONE, UCALL_UNHANDLED, }; #define UCALL_MAX_ARGS 7 +#define UCALL_BUFFER_LEN 1024 struct ucall { uint64_t cmd; uint64_t args[UCALL_MAX_ARGS]; + char buffer[UCALL_BUFFER_LEN]; /* Host virtual address of this struct. */ struct ucall *hva; @@ -32,6 +35,7 @@ void ucall_arch_do_ucall(vm_vaddr_t uc); void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu); void ucall(uint64_t cmd, int nargs, ...); +void ucall_fmt(uint64_t cmd, const char *fmt, ...); uint64_t get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc); void ucall_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa); int ucall_nr_pages_required(uint64_t page_size); @@ -47,8 +51,11 @@ int ucall_nr_pages_required(uint64_t page_size); #define GUEST_SYNC_ARGS(stage, arg1, arg2, arg3, arg4) \ ucall(UCALL_SYNC, 6, "hello", stage, arg1, arg2, arg3, arg4) #define GUEST_SYNC(stage) ucall(UCALL_SYNC, 2, "hello", stage) +#define GUEST_PRINTF(_fmt, _args...) ucall_fmt(UCALL_PRINTF, _fmt, ##_args) #define GUEST_DONE() ucall(UCALL_DONE, 0) +#define REPORT_GUEST_PRINTF(ucall) pr_info("%s", (ucall).buffer) + enum guest_assert_builtin_args { GUEST_ERROR_STRING, GUEST_FILE, diff --git a/tools/testing/selftests/kvm/lib/ucall_common.c b/tools/testing/selftests/kvm/lib/ucall_common.c index 77ada362273d7..b507db91139bf 100644 --- a/tools/testing/selftests/kvm/lib/ucall_common.c +++ b/tools/testing/selftests/kvm/lib/ucall_common.c @@ -75,6 +75,23 @@ static void ucall_free(struct ucall *uc) clear_bit(uc - ucall_pool->ucalls, ucall_pool->in_use); } +void ucall_fmt(uint64_t cmd, const char *fmt, ...) +{ + struct ucall *uc; + va_list va; + + uc = ucall_alloc(); + uc->cmd = cmd; + + va_start(va, fmt); + guest_vsnprintf(uc->buffer, UCALL_BUFFER_LEN, fmt, va); + va_end(va); + + ucall_arch_do_ucall((vm_vaddr_t)uc->hva); + + ucall_free(uc); +} + void ucall(uint64_t cmd, int nargs, ...) { struct ucall *uc; -- GitLab From 289c2b4db8f336b96d918eb0c548382aee71ed79 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:17 -0700 Subject: [PATCH 0704/3445] KVM: selftests: Add formatted guest assert support in ucall framework Add printf-based GUEST_ASSERT macros and accompanying host-side support to provide an assert-specific versions of GUEST_PRINTF(). To make it easier to parse assert messages, for humans and bots alike, preserve/use the same layout as host asserts, e.g. in the example below, the reported expression, file, line number, and message are from the guest assertion, not the host reporting of the assertion. The call stack still captures the host reporting, but capturing the guest stack is a less pressing concern, i.e. can be done in the future, and an optimal solution would capture *both* the host and guest stacks, i.e. capturing the host stack isn't an outright bug. Running soft int test ==== Test Assertion Failure ==== x86_64/svm_nested_soft_inject_test.c:39: regs->rip != (unsigned long)l2_guest_code_int pid=214104 tid=214104 errno=4 - Interrupted system call 1 0x0000000000401b35: run_test at svm_nested_soft_inject_test.c:191 2 0x00000000004017d2: main at svm_nested_soft_inject_test.c:212 3 0x0000000000415b03: __libc_start_call_main at libc-start.o:? 4 0x000000000041714f: __libc_start_main_impl at ??:? 5 0x0000000000401660: _start at ??:? Expected IRQ at RIP 0x401e50, received IRQ at 0x401e50 Don't bother sharing code between ucall_assert() and ucall_fmt(), as forwarding the variable arguments would either require using macros or building a va_list, i.e. would make the code less readable and/or require just as much copy+paste code anyways. Gate the new macros with a flag so that tests can more or less be switched over one-by-one. The slow conversion won't be perfect, e.g. library code won't pick up the flag, but the only asserts in library code are of the vanilla GUEST_ASSERT() variety, i.e. don't print out variables. Add a temporary alias to GUEST_ASSERT_1() to fudge around ARM's arch_timer.h header using GUEST_ASSERT_1(), thus thwarting any attempt to convert tests one-by-one. Link: https://lore.kernel.org/r/20230729003643.1053367-9-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/include/ucall_common.h | 48 +++++++++++++++++++ .../testing/selftests/kvm/lib/ucall_common.c | 22 +++++++++ 2 files changed, 70 insertions(+) diff --git a/tools/testing/selftests/kvm/include/ucall_common.h b/tools/testing/selftests/kvm/include/ucall_common.h index b5548aeba9f0c..4ce11c15285a9 100644 --- a/tools/testing/selftests/kvm/include/ucall_common.h +++ b/tools/testing/selftests/kvm/include/ucall_common.h @@ -36,6 +36,8 @@ void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu); void ucall(uint64_t cmd, int nargs, ...); void ucall_fmt(uint64_t cmd, const char *fmt, ...); +void ucall_assert(uint64_t cmd, const char *exp, const char *file, + unsigned int line, const char *fmt, ...); uint64_t get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc); void ucall_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa); int ucall_nr_pages_required(uint64_t page_size); @@ -63,6 +65,50 @@ enum guest_assert_builtin_args { GUEST_ASSERT_BUILTIN_NARGS }; +#ifdef USE_GUEST_ASSERT_PRINTF +#define ____GUEST_ASSERT(_condition, _exp, _fmt, _args...) \ +do { \ + if (!(_condition)) \ + ucall_assert(UCALL_ABORT, _exp, __FILE__, __LINE__, _fmt, ##_args); \ +} while (0) + +#define __GUEST_ASSERT(_condition, _fmt, _args...) \ + ____GUEST_ASSERT(_condition, #_condition, _fmt, ##_args) + +#define GUEST_ASSERT(_condition) \ + __GUEST_ASSERT(_condition, #_condition) + +#define GUEST_FAIL(_fmt, _args...) \ + ucall_assert(UCALL_ABORT, "Unconditional guest failure", \ + __FILE__, __LINE__, _fmt, ##_args) + +#define GUEST_ASSERT_EQ(a, b) \ +do { \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + ____GUEST_ASSERT(__a == __b, #a " == " #b, "%#lx != %#lx (%s != %s)", \ + (unsigned long)(__a), (unsigned long)(__b), #a, #b); \ +} while (0) + +#define GUEST_ASSERT_NE(a, b) \ +do { \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + ____GUEST_ASSERT(__a != __b, #a " != " #b, "%#lx == %#lx (%s == %s)", \ + (unsigned long)(__a), (unsigned long)(__b), #a, #b); \ +} while (0) + +#define REPORT_GUEST_ASSERT(ucall) \ + test_assert(false, (const char *)(ucall).args[GUEST_ERROR_STRING], \ + (const char *)(ucall).args[GUEST_FILE], \ + (ucall).args[GUEST_LINE], "%s", (ucall).buffer) + +/* FIXME: Drop this alias once the param-based guest asserts are gone. */ +#define GUEST_ASSERT_1(_condition, arg1) \ + __GUEST_ASSERT(_condition, "arg1 = 0x%lx", arg1) + +#else + #define __GUEST_ASSERT(_condition, _condstr, _nargs, _args...) \ do { \ if (!(_condition)) \ @@ -129,4 +175,6 @@ do { \ #define REPORT_GUEST_ASSERT_N(ucall, fmt, args...) \ __REPORT_GUEST_ASSERT((ucall), fmt, ##args) +#endif /* USE_GUEST_ASSERT_PRINTF */ + #endif /* SELFTEST_KVM_UCALL_COMMON_H */ diff --git a/tools/testing/selftests/kvm/lib/ucall_common.c b/tools/testing/selftests/kvm/lib/ucall_common.c index b507db91139bf..816a3fa109bfb 100644 --- a/tools/testing/selftests/kvm/lib/ucall_common.c +++ b/tools/testing/selftests/kvm/lib/ucall_common.c @@ -75,6 +75,28 @@ static void ucall_free(struct ucall *uc) clear_bit(uc - ucall_pool->ucalls, ucall_pool->in_use); } +void ucall_assert(uint64_t cmd, const char *exp, const char *file, + unsigned int line, const char *fmt, ...) +{ + struct ucall *uc; + va_list va; + + uc = ucall_alloc(); + uc->cmd = cmd; + + WRITE_ONCE(uc->args[GUEST_ERROR_STRING], (uint64_t)(exp)); + WRITE_ONCE(uc->args[GUEST_FILE], (uint64_t)(file)); + WRITE_ONCE(uc->args[GUEST_LINE], line); + + va_start(va, fmt); + guest_vsnprintf(uc->buffer, UCALL_BUFFER_LEN, fmt, va); + va_end(va); + + ucall_arch_do_ucall((vm_vaddr_t)uc->hva); + + ucall_free(uc); +} + void ucall_fmt(uint64_t cmd, const char *fmt, ...) { struct ucall *uc; -- GitLab From b35f4c73d389d3b04e5edf3d1fd041ed3070228b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 31 Jul 2023 13:30:24 -0700 Subject: [PATCH 0705/3445] KVM: selftests: Add arch ucall.h and inline simple arch hooks Add an architecture specific ucall.h and inline the simple arch hooks, e.g. the init hook for everything except ARM, and the actual "do ucall" hook for everything except x86 (which should be simple, but temporarily isn't due to carrying a workaround). Having a per-arch ucall header will allow adding a #define for the expected KVM exit reason for a ucall that is colocated (for everything except x86) with the ucall itself. Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20230731203026.1192091-2-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/include/aarch64/ucall.h | 18 ++++++++++++++++++ .../selftests/kvm/include/riscv/ucall.h | 18 ++++++++++++++++++ .../selftests/kvm/include/s390x/ucall.h | 17 +++++++++++++++++ .../selftests/kvm/include/ucall_common.h | 1 + .../selftests/kvm/include/x86_64/ucall.h | 11 +++++++++++ .../testing/selftests/kvm/lib/aarch64/ucall.c | 11 +---------- tools/testing/selftests/kvm/lib/riscv/ucall.c | 11 ----------- tools/testing/selftests/kvm/lib/s390x/ucall.c | 10 ---------- tools/testing/selftests/kvm/lib/x86_64/ucall.c | 4 ---- 9 files changed, 66 insertions(+), 35 deletions(-) create mode 100644 tools/testing/selftests/kvm/include/aarch64/ucall.h create mode 100644 tools/testing/selftests/kvm/include/riscv/ucall.h create mode 100644 tools/testing/selftests/kvm/include/s390x/ucall.h create mode 100644 tools/testing/selftests/kvm/include/x86_64/ucall.h diff --git a/tools/testing/selftests/kvm/include/aarch64/ucall.h b/tools/testing/selftests/kvm/include/aarch64/ucall.h new file mode 100644 index 0000000000000..fe65fdf4f0d3a --- /dev/null +++ b/tools/testing/selftests/kvm/include/aarch64/ucall.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef SELFTEST_KVM_UCALL_H +#define SELFTEST_KVM_UCALL_H + +#include "kvm_util_base.h" + +/* + * ucall_exit_mmio_addr holds per-VM values (global data is duplicated by each + * VM), it must not be accessed from host code. + */ +extern vm_vaddr_t *ucall_exit_mmio_addr; + +static inline void ucall_arch_do_ucall(vm_vaddr_t uc) +{ + WRITE_ONCE(*ucall_exit_mmio_addr, uc); +} + +#endif diff --git a/tools/testing/selftests/kvm/include/riscv/ucall.h b/tools/testing/selftests/kvm/include/riscv/ucall.h new file mode 100644 index 0000000000000..86ed0500972b7 --- /dev/null +++ b/tools/testing/selftests/kvm/include/riscv/ucall.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef SELFTEST_KVM_UCALL_H +#define SELFTEST_KVM_UCALL_H + +#include "processor.h" + +static inline void ucall_arch_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa) +{ +} + +static inline void ucall_arch_do_ucall(vm_vaddr_t uc) +{ + sbi_ecall(KVM_RISCV_SELFTESTS_SBI_EXT, + KVM_RISCV_SELFTESTS_SBI_UCALL, + uc, 0, 0, 0, 0, 0); +} + +#endif diff --git a/tools/testing/selftests/kvm/include/s390x/ucall.h b/tools/testing/selftests/kvm/include/s390x/ucall.h new file mode 100644 index 0000000000000..47ad4b1fbccba --- /dev/null +++ b/tools/testing/selftests/kvm/include/s390x/ucall.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef SELFTEST_KVM_UCALL_H +#define SELFTEST_KVM_UCALL_H + +#include "kvm_util_base.h" + +static inline void ucall_arch_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa) +{ +} + +static inline void ucall_arch_do_ucall(vm_vaddr_t uc) +{ + /* Exit via DIAGNOSE 0x501 (normally used for breakpoints) */ + asm volatile ("diag 0,%0,0x501" : : "a"(uc) : "memory"); +} + +#endif diff --git a/tools/testing/selftests/kvm/include/ucall_common.h b/tools/testing/selftests/kvm/include/ucall_common.h index 4ce11c15285a9..9e5948dab0304 100644 --- a/tools/testing/selftests/kvm/include/ucall_common.h +++ b/tools/testing/selftests/kvm/include/ucall_common.h @@ -7,6 +7,7 @@ #ifndef SELFTEST_KVM_UCALL_COMMON_H #define SELFTEST_KVM_UCALL_COMMON_H #include "test_util.h" +#include "ucall.h" /* Common ucalls */ enum { diff --git a/tools/testing/selftests/kvm/include/x86_64/ucall.h b/tools/testing/selftests/kvm/include/x86_64/ucall.h new file mode 100644 index 0000000000000..05cc69b0d5508 --- /dev/null +++ b/tools/testing/selftests/kvm/include/x86_64/ucall.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef SELFTEST_KVM_UCALL_H +#define SELFTEST_KVM_UCALL_H + +#include "kvm_util_base.h" + +static inline void ucall_arch_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa) +{ +} + +#endif diff --git a/tools/testing/selftests/kvm/lib/aarch64/ucall.c b/tools/testing/selftests/kvm/lib/aarch64/ucall.c index f212bd8ab93d8..ddab0ce89d4df 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/ucall.c +++ b/tools/testing/selftests/kvm/lib/aarch64/ucall.c @@ -6,11 +6,7 @@ */ #include "kvm_util.h" -/* - * ucall_exit_mmio_addr holds per-VM values (global data is duplicated by each - * VM), it must not be accessed from host code. - */ -static vm_vaddr_t *ucall_exit_mmio_addr; +vm_vaddr_t *ucall_exit_mmio_addr; void ucall_arch_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa) { @@ -23,11 +19,6 @@ void ucall_arch_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa) write_guest_global(vm, ucall_exit_mmio_addr, (vm_vaddr_t *)mmio_gva); } -void ucall_arch_do_ucall(vm_vaddr_t uc) -{ - WRITE_ONCE(*ucall_exit_mmio_addr, uc); -} - void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu) { struct kvm_run *run = vcpu->run; diff --git a/tools/testing/selftests/kvm/lib/riscv/ucall.c b/tools/testing/selftests/kvm/lib/riscv/ucall.c index 9a3476a2dfca4..fe6d1004f018c 100644 --- a/tools/testing/selftests/kvm/lib/riscv/ucall.c +++ b/tools/testing/selftests/kvm/lib/riscv/ucall.c @@ -10,10 +10,6 @@ #include "kvm_util.h" #include "processor.h" -void ucall_arch_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa) -{ -} - struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, @@ -40,13 +36,6 @@ struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0, return ret; } -void ucall_arch_do_ucall(vm_vaddr_t uc) -{ - sbi_ecall(KVM_RISCV_SELFTESTS_SBI_EXT, - KVM_RISCV_SELFTESTS_SBI_UCALL, - uc, 0, 0, 0, 0, 0); -} - void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu) { struct kvm_run *run = vcpu->run; diff --git a/tools/testing/selftests/kvm/lib/s390x/ucall.c b/tools/testing/selftests/kvm/lib/s390x/ucall.c index a7f02dc372cf7..cca98734653d4 100644 --- a/tools/testing/selftests/kvm/lib/s390x/ucall.c +++ b/tools/testing/selftests/kvm/lib/s390x/ucall.c @@ -6,16 +6,6 @@ */ #include "kvm_util.h" -void ucall_arch_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa) -{ -} - -void ucall_arch_do_ucall(vm_vaddr_t uc) -{ - /* Exit via DIAGNOSE 0x501 (normally used for breakpoints) */ - asm volatile ("diag 0,%0,0x501" : : "a"(uc) : "memory"); -} - void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu) { struct kvm_run *run = vcpu->run; diff --git a/tools/testing/selftests/kvm/lib/x86_64/ucall.c b/tools/testing/selftests/kvm/lib/x86_64/ucall.c index a53df3ece2f8b..1265cecc7dd10 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/ucall.c +++ b/tools/testing/selftests/kvm/lib/x86_64/ucall.c @@ -8,10 +8,6 @@ #define UCALL_PIO_PORT ((uint16_t)0x1000) -void ucall_arch_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa) -{ -} - void ucall_arch_do_ucall(vm_vaddr_t uc) { /* -- GitLab From edb5b700f9f8a21e57aef14cf795fb958cc38628 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 31 Jul 2023 13:30:25 -0700 Subject: [PATCH 0706/3445] KVM: selftests: Add #define of expected KVM exit reason for ucall Define the expected architecture specific exit reason for a successful ucall so that common tests can assert that a ucall occurred without the test needing to implement arch specific code. Suggested-by: Andrew Jones Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20230731203026.1192091-3-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/include/aarch64/ucall.h | 2 ++ tools/testing/selftests/kvm/include/riscv/ucall.h | 2 ++ tools/testing/selftests/kvm/include/s390x/ucall.h | 2 ++ tools/testing/selftests/kvm/include/x86_64/ucall.h | 2 ++ 4 files changed, 8 insertions(+) diff --git a/tools/testing/selftests/kvm/include/aarch64/ucall.h b/tools/testing/selftests/kvm/include/aarch64/ucall.h index fe65fdf4f0d3a..4b68f37efd368 100644 --- a/tools/testing/selftests/kvm/include/aarch64/ucall.h +++ b/tools/testing/selftests/kvm/include/aarch64/ucall.h @@ -4,6 +4,8 @@ #include "kvm_util_base.h" +#define UCALL_EXIT_REASON KVM_EXIT_MMIO + /* * ucall_exit_mmio_addr holds per-VM values (global data is duplicated by each * VM), it must not be accessed from host code. diff --git a/tools/testing/selftests/kvm/include/riscv/ucall.h b/tools/testing/selftests/kvm/include/riscv/ucall.h index 86ed0500972b7..be46eb32ec277 100644 --- a/tools/testing/selftests/kvm/include/riscv/ucall.h +++ b/tools/testing/selftests/kvm/include/riscv/ucall.h @@ -4,6 +4,8 @@ #include "processor.h" +#define UCALL_EXIT_REASON KVM_EXIT_RISCV_SBI + static inline void ucall_arch_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa) { } diff --git a/tools/testing/selftests/kvm/include/s390x/ucall.h b/tools/testing/selftests/kvm/include/s390x/ucall.h index 47ad4b1fbccba..b231bf2e49d62 100644 --- a/tools/testing/selftests/kvm/include/s390x/ucall.h +++ b/tools/testing/selftests/kvm/include/s390x/ucall.h @@ -4,6 +4,8 @@ #include "kvm_util_base.h" +#define UCALL_EXIT_REASON KVM_EXIT_S390_SIEIC + static inline void ucall_arch_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa) { } diff --git a/tools/testing/selftests/kvm/include/x86_64/ucall.h b/tools/testing/selftests/kvm/include/x86_64/ucall.h index 05cc69b0d5508..06b244bd06eeb 100644 --- a/tools/testing/selftests/kvm/include/x86_64/ucall.h +++ b/tools/testing/selftests/kvm/include/x86_64/ucall.h @@ -4,6 +4,8 @@ #include "kvm_util_base.h" +#define UCALL_EXIT_REASON KVM_EXIT_IO + static inline void ucall_arch_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa) { } -- GitLab From 5d1d46f9d56fb567718175cb0cb7a084d444a9d4 Mon Sep 17 00:00:00 2001 From: Aaron Lewis Date: Mon, 31 Jul 2023 13:30:26 -0700 Subject: [PATCH 0707/3445] KVM: selftests: Add a selftest for guest prints and formatted asserts Add a test to exercise the various features in KVM selftest's local snprintf() and compare them to LIBC's snprintf() to ensure they behave the same. This is not an exhaustive test. KVM's local snprintf() does not implement all the features LIBC does, e.g. KVM's local snprintf() does not support floats or doubles, so testing for those features were excluded. Testing was added for the features that are expected to work to support a minimal version of printf() in the guest. Signed-off-by: Aaron Lewis [sean: use UCALL_EXIT_REASON, enable for all architectures] Link: https://lore.kernel.org/r/20230731203026.1192091-4-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/Makefile | 4 + .../testing/selftests/kvm/guest_print_test.c | 221 ++++++++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 tools/testing/selftests/kvm/guest_print_test.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index f65889f5a0836..77026907968fc 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -123,6 +123,7 @@ TEST_GEN_PROGS_x86_64 += access_tracking_perf_test TEST_GEN_PROGS_x86_64 += demand_paging_test TEST_GEN_PROGS_x86_64 += dirty_log_test TEST_GEN_PROGS_x86_64 += dirty_log_perf_test +TEST_GEN_PROGS_x86_64 += guest_print_test TEST_GEN_PROGS_x86_64 += hardware_disable_test TEST_GEN_PROGS_x86_64 += kvm_create_max_vcpus TEST_GEN_PROGS_x86_64 += kvm_page_table_test @@ -153,6 +154,7 @@ TEST_GEN_PROGS_aarch64 += access_tracking_perf_test TEST_GEN_PROGS_aarch64 += demand_paging_test TEST_GEN_PROGS_aarch64 += dirty_log_test TEST_GEN_PROGS_aarch64 += dirty_log_perf_test +TEST_GEN_PROGS_aarch64 += guest_print_test TEST_GEN_PROGS_aarch64 += kvm_create_max_vcpus TEST_GEN_PROGS_aarch64 += kvm_page_table_test TEST_GEN_PROGS_aarch64 += memslot_modification_stress_test @@ -169,6 +171,7 @@ TEST_GEN_PROGS_s390x += s390x/tprot TEST_GEN_PROGS_s390x += s390x/cmma_test TEST_GEN_PROGS_s390x += demand_paging_test TEST_GEN_PROGS_s390x += dirty_log_test +TEST_GEN_PROGS_s390x += guest_print_test TEST_GEN_PROGS_s390x += kvm_create_max_vcpus TEST_GEN_PROGS_s390x += kvm_page_table_test TEST_GEN_PROGS_s390x += rseq_test @@ -177,6 +180,7 @@ TEST_GEN_PROGS_s390x += kvm_binary_stats_test TEST_GEN_PROGS_riscv += demand_paging_test TEST_GEN_PROGS_riscv += dirty_log_test +TEST_GEN_PROGS_riscv += guest_print_test TEST_GEN_PROGS_riscv += kvm_create_max_vcpus TEST_GEN_PROGS_riscv += kvm_page_table_test TEST_GEN_PROGS_riscv += set_memory_region_test diff --git a/tools/testing/selftests/kvm/guest_print_test.c b/tools/testing/selftests/kvm/guest_print_test.c new file mode 100644 index 0000000000000..267e01d057fb4 --- /dev/null +++ b/tools/testing/selftests/kvm/guest_print_test.c @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * A test for GUEST_PRINTF + * + * Copyright 2022, Google, Inc. and/or its affiliates. + */ +#define USE_GUEST_ASSERT_PRINTF 1 + +#include +#include +#include +#include +#include + +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" + +struct guest_vals { + uint64_t a; + uint64_t b; + uint64_t type; +}; + +static struct guest_vals vals; + +/* GUEST_PRINTF()/GUEST_ASSERT_FMT() does not support float or double. */ +#define TYPE_LIST \ +TYPE(test_type_i64, I64, "%ld", int64_t) \ +TYPE(test_type_u64, U64u, "%lu", uint64_t) \ +TYPE(test_type_x64, U64x, "0x%lx", uint64_t) \ +TYPE(test_type_X64, U64X, "0x%lX", uint64_t) \ +TYPE(test_type_u32, U32u, "%u", uint32_t) \ +TYPE(test_type_x32, U32x, "0x%x", uint32_t) \ +TYPE(test_type_X32, U32X, "0x%X", uint32_t) \ +TYPE(test_type_int, INT, "%d", int) \ +TYPE(test_type_char, CHAR, "%c", char) \ +TYPE(test_type_str, STR, "'%s'", const char *) \ +TYPE(test_type_ptr, PTR, "%p", uintptr_t) + +enum args_type { +#define TYPE(fn, ext, fmt_t, T) TYPE_##ext, + TYPE_LIST +#undef TYPE +}; + +static void run_test(struct kvm_vcpu *vcpu, const char *expected_printf, + const char *expected_assert); + +#define BUILD_TYPE_STRINGS_AND_HELPER(fn, ext, fmt_t, T) \ +const char *PRINTF_FMT_##ext = "Got params a = " fmt_t " and b = " fmt_t; \ +const char *ASSERT_FMT_##ext = "Expected " fmt_t ", got " fmt_t " instead"; \ +static void fn(struct kvm_vcpu *vcpu, T a, T b) \ +{ \ + char expected_printf[UCALL_BUFFER_LEN]; \ + char expected_assert[UCALL_BUFFER_LEN]; \ + \ + snprintf(expected_printf, UCALL_BUFFER_LEN, PRINTF_FMT_##ext, a, b); \ + snprintf(expected_assert, UCALL_BUFFER_LEN, ASSERT_FMT_##ext, a, b); \ + vals = (struct guest_vals){ (uint64_t)a, (uint64_t)b, TYPE_##ext }; \ + sync_global_to_guest(vcpu->vm, vals); \ + run_test(vcpu, expected_printf, expected_assert); \ +} + +#define TYPE(fn, ext, fmt_t, T) \ + BUILD_TYPE_STRINGS_AND_HELPER(fn, ext, fmt_t, T) + TYPE_LIST +#undef TYPE + +static void guest_code(void) +{ + while (1) { + switch (vals.type) { +#define TYPE(fn, ext, fmt_t, T) \ + case TYPE_##ext: \ + GUEST_PRINTF(PRINTF_FMT_##ext, vals.a, vals.b); \ + __GUEST_ASSERT(vals.a == vals.b, \ + ASSERT_FMT_##ext, vals.a, vals.b); \ + break; + TYPE_LIST +#undef TYPE + default: + GUEST_SYNC(vals.type); + } + + GUEST_DONE(); + } +} + +/* + * Unfortunately this gets a little messy because 'assert_msg' doesn't + * just contains the matching string, it also contains additional assert + * info. Fortunately the part that matches should be at the very end of + * 'assert_msg'. + */ +static void ucall_abort(const char *assert_msg, const char *expected_assert_msg) +{ + int len_str = strlen(assert_msg); + int len_substr = strlen(expected_assert_msg); + int offset = len_str - len_substr; + + TEST_ASSERT(len_substr <= len_str, + "Expected '%s' to be a substring of '%s'\n", + assert_msg, expected_assert_msg); + + TEST_ASSERT(strcmp(&assert_msg[offset], expected_assert_msg) == 0, + "Unexpected mismatch. Expected: '%s', got: '%s'", + expected_assert_msg, &assert_msg[offset]); +} + +static void run_test(struct kvm_vcpu *vcpu, const char *expected_printf, + const char *expected_assert) +{ + struct kvm_run *run = vcpu->run; + struct ucall uc; + + while (1) { + vcpu_run(vcpu); + + TEST_ASSERT(run->exit_reason == UCALL_EXIT_REASON, + "Unexpected exit reason: %u (%s),\n", + run->exit_reason, exit_reason_str(run->exit_reason)); + + switch (get_ucall(vcpu, &uc)) { + case UCALL_SYNC: + TEST_FAIL("Unknown 'args_type' = %lu", uc.args[1]); + break; + case UCALL_PRINTF: + TEST_ASSERT(strcmp(uc.buffer, expected_printf) == 0, + "Unexpected mismatch. Expected: '%s', got: '%s'", + expected_printf, uc.buffer); + break; + case UCALL_ABORT: + ucall_abort(uc.buffer, expected_assert); + break; + case UCALL_DONE: + return; + default: + TEST_FAIL("Unknown ucall %lu", uc.cmd); + } + } +} + +static void guest_code_limits(void) +{ + char test_str[UCALL_BUFFER_LEN + 10]; + + memset(test_str, 'a', sizeof(test_str)); + test_str[sizeof(test_str) - 1] = 0; + + GUEST_PRINTF("%s", test_str); +} + +static void test_limits(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_run *run; + struct kvm_vm *vm; + struct ucall uc; + + vm = vm_create_with_one_vcpu(&vcpu, guest_code_limits); + run = vcpu->run; + vcpu_run(vcpu); + + TEST_ASSERT(run->exit_reason == UCALL_EXIT_REASON, + "Unexpected exit reason: %u (%s),\n", + run->exit_reason, exit_reason_str(run->exit_reason)); + + TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_ABORT, + "Unexpected ucall command: %lu, Expected: %u (UCALL_ABORT)\n", + uc.cmd, UCALL_ABORT); + + kvm_vm_free(vm); +} + +int main(int argc, char *argv[]) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + + vm = vm_create_with_one_vcpu(&vcpu, guest_code); + + test_type_i64(vcpu, -1, -1); + test_type_i64(vcpu, -1, 1); + test_type_i64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef); + test_type_i64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee); + + test_type_u64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef); + test_type_u64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee); + test_type_x64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef); + test_type_x64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee); + test_type_X64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef); + test_type_X64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee); + + test_type_u32(vcpu, 0x90abcdef, 0x90abcdef); + test_type_u32(vcpu, 0x90abcdef, 0x90abcdee); + test_type_x32(vcpu, 0x90abcdef, 0x90abcdef); + test_type_x32(vcpu, 0x90abcdef, 0x90abcdee); + test_type_X32(vcpu, 0x90abcdef, 0x90abcdef); + test_type_X32(vcpu, 0x90abcdef, 0x90abcdee); + + test_type_int(vcpu, -1, -1); + test_type_int(vcpu, -1, 1); + test_type_int(vcpu, 1, 1); + + test_type_char(vcpu, 'a', 'a'); + test_type_char(vcpu, 'a', 'A'); + test_type_char(vcpu, 'a', 'b'); + + test_type_str(vcpu, "foo", "foo"); + test_type_str(vcpu, "foo", "bar"); + + test_type_ptr(vcpu, 0x1234567890abcdef, 0x1234567890abcdef); + test_type_ptr(vcpu, 0x1234567890abcdef, 0x1234567890abcdee); + + kvm_vm_free(vm); + + test_limits(); + + return 0; +} -- GitLab From db44e1c871bcf6228b9447aada421088e036692a Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:19 -0700 Subject: [PATCH 0708/3445] KVM: selftests: Convert aarch_timer to printf style GUEST_ASSERT Convert ARM's aarch_timer test to use printf-based GUEST_ASSERT(). To maintain existing functionality, manually print the host information, e.g. stage and iteration, to stderr prior to reporting the guest assert. Link: https://lore.kernel.org/r/20230729003643.1053367-11-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/aarch64/arch_timer.c | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/arch_timer.c b/tools/testing/selftests/kvm/aarch64/arch_timer.c index 8ef370924a02e..b53bcf126e6a6 100644 --- a/tools/testing/selftests/kvm/aarch64/arch_timer.c +++ b/tools/testing/selftests/kvm/aarch64/arch_timer.c @@ -19,6 +19,7 @@ * * Copyright (c) 2021, Google LLC. */ +#define USE_GUEST_ASSERT_PRINTF 1 #define _GNU_SOURCE @@ -155,11 +156,13 @@ static void guest_validate_irq(unsigned int intid, xcnt_diff_us = cycles_to_usec(xcnt - shared_data->xcnt); /* Make sure we are dealing with the correct timer IRQ */ - GUEST_ASSERT_2(intid == timer_irq, intid, timer_irq); + GUEST_ASSERT_EQ(intid, timer_irq); /* Basic 'timer condition met' check */ - GUEST_ASSERT_3(xcnt >= cval, xcnt, cval, xcnt_diff_us); - GUEST_ASSERT_1(xctl & CTL_ISTATUS, xctl); + __GUEST_ASSERT(xcnt >= cval, + "xcnt = 0x%llx, cval = 0x%llx, xcnt_diff_us = 0x%llx", + xcnt, cval, xcnt_diff_us); + __GUEST_ASSERT(xctl & CTL_ISTATUS, "xcnt = 0x%llx", xcnt); WRITE_ONCE(shared_data->nr_iter, shared_data->nr_iter + 1); } @@ -192,8 +195,7 @@ static void guest_run_stage(struct test_vcpu_shared_data *shared_data, TIMER_TEST_ERR_MARGIN_US); irq_iter = READ_ONCE(shared_data->nr_iter); - GUEST_ASSERT_2(config_iter + 1 == irq_iter, - config_iter + 1, irq_iter); + GUEST_ASSERT_EQ(config_iter + 1, irq_iter); } } @@ -243,13 +245,9 @@ static void *test_vcpu_run(void *arg) break; case UCALL_ABORT: sync_global_from_guest(vm, *shared_data); - REPORT_GUEST_ASSERT_N(uc, "values: %lu, %lu; %lu, vcpu %u; stage; %u; iter: %u", - GUEST_ASSERT_ARG(uc, 0), - GUEST_ASSERT_ARG(uc, 1), - GUEST_ASSERT_ARG(uc, 2), - vcpu_idx, - shared_data->guest_stage, - shared_data->nr_iter); + fprintf(stderr, "Guest assert failed, vcpu %u; stage; %u; iter: %u\n", + vcpu_idx, shared_data->guest_stage, shared_data->nr_iter); + REPORT_GUEST_ASSERT(uc); break; default: TEST_FAIL("Unexpected guest exit\n"); -- GitLab From bac9aeecc387a1436567b6e74f8257f7e8c4d194 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:20 -0700 Subject: [PATCH 0709/3445] KVM: selftests: Convert debug-exceptions to printf style GUEST_ASSERT Convert ARM's debug exceptions test to use printf-based GUEST_ASSERT(). Opportunistically Use GUEST_ASSERT_EQ() in guest_code_ss() so that the expected vs. actual values get printed out. Link: https://lore.kernel.org/r/20230729003643.1053367-12-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/aarch64/debug-exceptions.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/debug-exceptions.c b/tools/testing/selftests/kvm/aarch64/debug-exceptions.c index 637be796086f7..fdd5b05e1b0e5 100644 --- a/tools/testing/selftests/kvm/aarch64/debug-exceptions.c +++ b/tools/testing/selftests/kvm/aarch64/debug-exceptions.c @@ -1,4 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 +#define USE_GUEST_ASSERT_PRINTF 1 + #include #include #include @@ -365,7 +367,7 @@ static void guest_wp_handler(struct ex_regs *regs) static void guest_ss_handler(struct ex_regs *regs) { - GUEST_ASSERT_1(ss_idx < 4, ss_idx); + __GUEST_ASSERT(ss_idx < 4, "Expected index < 4, got '%u'", ss_idx); ss_addr[ss_idx++] = regs->pc; regs->pstate |= SPSR_SS; } @@ -410,8 +412,8 @@ static void guest_code_ss(int test_cnt) /* Userspace disables Single Step when the end is nigh. */ asm volatile("iter_ss_end:\n"); - GUEST_ASSERT(bvr == w_bvr); - GUEST_ASSERT(wvr == w_wvr); + GUEST_ASSERT_EQ(bvr, w_bvr); + GUEST_ASSERT_EQ(wvr, w_wvr); } GUEST_DONE(); } @@ -450,7 +452,7 @@ static void test_guest_debug_exceptions(uint8_t bpn, uint8_t wpn, uint8_t ctx_bp vcpu_run(vcpu); switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - REPORT_GUEST_ASSERT_2(uc, "values: %#lx, %#lx"); + REPORT_GUEST_ASSERT(uc); break; case UCALL_DONE: goto done; -- GitLab From af5b41b97f1cc9d766f700197955965872aba4a3 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:21 -0700 Subject: [PATCH 0710/3445] KVM: selftests: Convert ARM's hypercalls test to printf style GUEST_ASSERT Convert ARM's hypercalls test to use printf-based GUEST_ASSERT(). Opportunistically use GUEST_FAIL() to complain about an unexpected stage. Link: https://lore.kernel.org/r/20230729003643.1053367-13-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/aarch64/hypercalls.c | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c index bef1499fb4654..94555a7d3c7ee 100644 --- a/tools/testing/selftests/kvm/aarch64/hypercalls.c +++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c @@ -8,6 +8,7 @@ * hypercalls are properly masked or unmasked to the guest when disabled or * enabled from the KVM userspace, respectively. */ +#define USE_GUEST_ASSERT_PRINTF 1 #include #include @@ -105,15 +106,17 @@ static void guest_test_hvc(const struct test_hvc_info *hc_info) switch (stage) { case TEST_STAGE_HVC_IFACE_FEAT_DISABLED: case TEST_STAGE_HVC_IFACE_FALSE_INFO: - GUEST_ASSERT_3(res.a0 == SMCCC_RET_NOT_SUPPORTED, - res.a0, hc_info->func_id, hc_info->arg1); + __GUEST_ASSERT(res.a0 == SMCCC_RET_NOT_SUPPORTED, + "a0 = 0x%lx, func_id = 0x%x, arg1 = 0x%llx, stage = %u", + res.a0, hc_info->func_id, hc_info->arg1, stage); break; case TEST_STAGE_HVC_IFACE_FEAT_ENABLED: - GUEST_ASSERT_3(res.a0 != SMCCC_RET_NOT_SUPPORTED, - res.a0, hc_info->func_id, hc_info->arg1); + __GUEST_ASSERT(res.a0 != SMCCC_RET_NOT_SUPPORTED, + "a0 = 0x%lx, func_id = 0x%x, arg1 = 0x%llx, stage = %u", + res.a0, hc_info->func_id, hc_info->arg1, stage); break; default: - GUEST_ASSERT_1(0, stage); + GUEST_FAIL("Unexpected stage = %u", stage); } } } @@ -132,7 +135,7 @@ static void guest_code(void) guest_test_hvc(false_hvc_info); break; default: - GUEST_ASSERT_1(0, stage); + GUEST_FAIL("Unexpected stage = %u", stage); } GUEST_SYNC(stage); @@ -290,10 +293,7 @@ static void test_run(void) guest_done = true; break; case UCALL_ABORT: - REPORT_GUEST_ASSERT_N(uc, "values: 0x%lx, 0x%lx; 0x%lx, stage: %u", - GUEST_ASSERT_ARG(uc, 0), - GUEST_ASSERT_ARG(uc, 1), - GUEST_ASSERT_ARG(uc, 2), stage); + REPORT_GUEST_ASSERT(uc); break; default: TEST_FAIL("Unexpected guest exit\n"); -- GitLab From df27f6b45454c02919b84dfe3ffad3f665108d23 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:22 -0700 Subject: [PATCH 0711/3445] KVM: selftests: Convert ARM's page fault test to printf style GUEST_ASSERT Use GUEST_FAIL() in ARM's page fault test to report unexpected faults. Link: https://lore.kernel.org/r/20230729003643.1053367-14-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/aarch64/page_fault_test.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/page_fault_test.c b/tools/testing/selftests/kvm/aarch64/page_fault_test.c index e5bb8767d2cb5..0b0dd90feae5c 100644 --- a/tools/testing/selftests/kvm/aarch64/page_fault_test.c +++ b/tools/testing/selftests/kvm/aarch64/page_fault_test.c @@ -7,6 +7,7 @@ * hugetlbfs with a hole). It checks that the expected handling method is * called (e.g., uffd faults with the right address and write/read flag). */ +#define USE_GUEST_ASSERT_PRINTF 1 #define _GNU_SOURCE #include @@ -293,12 +294,12 @@ static void guest_code(struct test_desc *test) static void no_dabt_handler(struct ex_regs *regs) { - GUEST_ASSERT_1(false, read_sysreg(far_el1)); + GUEST_FAIL("Unexpected dabt, far_el1 = 0x%llx", read_sysreg(far_el1)); } static void no_iabt_handler(struct ex_regs *regs) { - GUEST_ASSERT_1(false, regs->pc); + GUEST_FAIL("Unexpected iabt, pc = 0x%lx", regs->pc); } static struct uffd_args { @@ -679,7 +680,7 @@ static void vcpu_run_loop(struct kvm_vm *vm, struct kvm_vcpu *vcpu, } break; case UCALL_ABORT: - REPORT_GUEST_ASSERT_2(uc, "values: %#lx, %#lx"); + REPORT_GUEST_ASSERT(uc); break; case UCALL_DONE: goto done; -- GitLab From d0ad3bacc523cd780d573c890ebf3b14cec5df22 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:23 -0700 Subject: [PATCH 0712/3445] KVM: selftests: Convert ARM's vGIC IRQ test to printf style GUEST_ASSERT Use printf-based guest assert reporting in ARM's vGIC IRQ test. Note, this is not as innocuous as it looks! The printf-based version of GUEST_ASSERT_EQ() ensures the expressions are evaluated only once, whereas the old version did not! Link: https://lore.kernel.org/r/20230729003643.1053367-15-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/aarch64/vgic_irq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/aarch64/vgic_irq.c b/tools/testing/selftests/kvm/aarch64/vgic_irq.c index 90d854e0fcffe..67da33aa6d17d 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_irq.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_irq.c @@ -7,6 +7,7 @@ * host to inject a specific intid via a GUEST_SYNC call, and then checks that * it received it. */ +#define USE_GUEST_ASSERT_PRINTF 1 #include #include @@ -781,7 +782,7 @@ static void test_vgic(uint32_t nr_irqs, bool level_sensitive, bool eoi_split) run_guest_cmd(vcpu, gic_fd, &inject_args, &args); break; case UCALL_ABORT: - REPORT_GUEST_ASSERT_2(uc, "values: %#lx, %#lx"); + REPORT_GUEST_ASSERT(uc); break; case UCALL_DONE: goto done; -- GitLab From c55a475d5fc42931992b667aa16bed2db6058d06 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:24 -0700 Subject: [PATCH 0713/3445] KVM: selftests: Convert the memslot performance test to printf guest asserts Use the printf-based GUEST_ASSERT_EQ() in the memslot perf test instead of an half-baked open code version. Link: https://lore.kernel.org/r/20230729003643.1053367-16-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/memslot_perf_test.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/memslot_perf_test.c b/tools/testing/selftests/kvm/memslot_perf_test.c index 4210cd21d1597..55f1bc70e5719 100644 --- a/tools/testing/selftests/kvm/memslot_perf_test.c +++ b/tools/testing/selftests/kvm/memslot_perf_test.c @@ -6,6 +6,8 @@ * * Basic guest setup / host vCPU thread code lifted from set_memory_region_test. */ +#define USE_GUEST_ASSERT_PRINTF 1 + #include #include #include @@ -157,7 +159,7 @@ static void *vcpu_worker(void *__data) goto done; break; case UCALL_ABORT: - REPORT_GUEST_ASSERT_1(uc, "val = %lu"); + REPORT_GUEST_ASSERT(uc); break; case UCALL_DONE: goto done; @@ -560,7 +562,7 @@ static void guest_code_test_memslot_rw(void) ptr < MEM_TEST_GPA + MEM_TEST_SIZE; ptr += page_size) { uint64_t val = *(uint64_t *)ptr; - GUEST_ASSERT_1(val == MEM_TEST_VAL_2, val); + GUEST_ASSERT_EQ(val, MEM_TEST_VAL_2); *(uint64_t *)ptr = 0; } -- GitLab From 428c76c769fa652e2186de464c74e34daede489f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:25 -0700 Subject: [PATCH 0714/3445] KVM: selftests: Convert s390's memop test to printf style GUEST_ASSERT Convert s390's memop test to printf-based GUEST_ASSERT, and opportunistically use GUEST_FAIL() to report invalid sizes. Link: https://lore.kernel.org/r/20230729003643.1053367-17-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/s390x/memop.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/s390x/memop.c b/tools/testing/selftests/kvm/s390x/memop.c index de73dc0309051..a49173907cec2 100644 --- a/tools/testing/selftests/kvm/s390x/memop.c +++ b/tools/testing/selftests/kvm/s390x/memop.c @@ -4,6 +4,7 @@ * * Copyright (C) 2019, Red Hat, Inc. */ +#define USE_GUEST_ASSERT_PRINTF 1 #include #include @@ -279,7 +280,7 @@ enum stage { vcpu_run(__vcpu); \ get_ucall(__vcpu, &uc); \ if (uc.cmd == UCALL_ABORT) { \ - REPORT_GUEST_ASSERT_2(uc, "hints: %lu, %lu"); \ + REPORT_GUEST_ASSERT(uc); \ } \ TEST_ASSERT_EQ(uc.cmd, UCALL_SYNC); \ TEST_ASSERT_EQ(uc.args[1], __stage); \ @@ -469,7 +470,7 @@ static __uint128_t cut_to_size(int size, __uint128_t val) case 16: return val; } - GUEST_ASSERT_1(false, "Invalid size"); + GUEST_FAIL("Invalid size = %u", size); return 0; } @@ -598,7 +599,7 @@ static bool _cmpxchg(int size, void *target, __uint128_t *old_addr, __uint128_t return ret; } } - GUEST_ASSERT_1(false, "Invalid size"); + GUEST_FAIL("Invalid size = %u", size); return 0; } -- GitLab From 5f82bbab84adcb8990f17503393628a210086b2c Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:26 -0700 Subject: [PATCH 0715/3445] KVM: selftests: Convert s390's tprot test to printf style GUEST_ASSERT Convert s390's tprot test to printf-based GUEST_ASSERT. Link: https://lore.kernel.org/r/20230729003643.1053367-18-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/s390x/tprot.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/s390x/tprot.c b/tools/testing/selftests/kvm/s390x/tprot.c index 40d3ea16c052f..c12c6824d9636 100644 --- a/tools/testing/selftests/kvm/s390x/tprot.c +++ b/tools/testing/selftests/kvm/s390x/tprot.c @@ -4,6 +4,7 @@ * * Copyright IBM Corp. 2021 */ +#define USE_GUEST_ASSERT_PRINTF 1 #include #include "test_util.h" @@ -156,7 +157,9 @@ static enum stage perform_next_stage(int *i, bool mapped_0) !mapped_0; if (!skip) { result = test_protection(tests[*i].addr, tests[*i].key); - GUEST_ASSERT_2(result == tests[*i].expected, *i, result); + __GUEST_ASSERT(result == tests[*i].expected, + "Wanted %u, got %u, for i = %u", + tests[*i].expected, result, *i); } } return stage; @@ -190,7 +193,7 @@ static void guest_code(void) vcpu_run(__vcpu); \ get_ucall(__vcpu, &uc); \ if (uc.cmd == UCALL_ABORT) \ - REPORT_GUEST_ASSERT_2(uc, "hints: %lu, %lu"); \ + REPORT_GUEST_ASSERT(uc); \ TEST_ASSERT_EQ(uc.cmd, UCALL_SYNC); \ TEST_ASSERT_EQ(uc.args[1], __stage); \ }) -- GitLab From 9291c9cef5b52b64a20f92ea63341d903f0ae328 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:27 -0700 Subject: [PATCH 0716/3445] KVM: selftests: Convert set_memory_region_test to printf-based GUEST_ASSERT Convert set_memory_region_test to print-based GUEST_ASSERT, using a combo of newfangled macros to report (hopefully) useful information. Link: https://lore.kernel.org/r/20230729003643.1053367-19-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/set_memory_region_test.c | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/kvm/set_memory_region_test.c b/tools/testing/selftests/kvm/set_memory_region_test.c index a849ce23ca975..dd8f4bac9df8a 100644 --- a/tools/testing/selftests/kvm/set_memory_region_test.c +++ b/tools/testing/selftests/kvm/set_memory_region_test.c @@ -1,4 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 +#define USE_GUEST_ASSERT_PRINTF 1 + #define _GNU_SOURCE /* for program_invocation_short_name */ #include #include @@ -88,7 +90,7 @@ static void *vcpu_worker(void *data) } if (run->exit_reason == KVM_EXIT_IO && cmd == UCALL_ABORT) - REPORT_GUEST_ASSERT_1(uc, "val = %lu"); + REPORT_GUEST_ASSERT(uc); return NULL; } @@ -156,19 +158,22 @@ static void guest_code_move_memory_region(void) * window where the memslot is invalid is usually quite small. */ val = guest_spin_on_val(0); - GUEST_ASSERT_1(val == 1 || val == MMIO_VAL, val); + __GUEST_ASSERT(val == 1 || val == MMIO_VAL, + "Expected '1' or MMIO ('%llx'), got '%llx'", MMIO_VAL, val); /* Spin until the misaligning memory region move completes. */ val = guest_spin_on_val(MMIO_VAL); - GUEST_ASSERT_1(val == 1 || val == 0, val); + __GUEST_ASSERT(val == 1 || val == 0, + "Expected '0' or '1' (no MMIO), got '%llx'", val); /* Spin until the memory region starts to get re-aligned. */ val = guest_spin_on_val(0); - GUEST_ASSERT_1(val == 1 || val == MMIO_VAL, val); + __GUEST_ASSERT(val == 1 || val == MMIO_VAL, + "Expected '1' or MMIO ('%llx'), got '%llx'", MMIO_VAL, val); /* Spin until the re-aligning memory region move completes. */ val = guest_spin_on_val(MMIO_VAL); - GUEST_ASSERT_1(val == 1, val); + GUEST_ASSERT_EQ(val, 1); GUEST_DONE(); } @@ -224,15 +229,15 @@ static void guest_code_delete_memory_region(void) /* Spin until the memory region is deleted. */ val = guest_spin_on_val(0); - GUEST_ASSERT_1(val == MMIO_VAL, val); + GUEST_ASSERT_EQ(val, MMIO_VAL); /* Spin until the memory region is recreated. */ val = guest_spin_on_val(MMIO_VAL); - GUEST_ASSERT_1(val == 0, val); + GUEST_ASSERT_EQ(val, 0); /* Spin until the memory region is deleted. */ val = guest_spin_on_val(0); - GUEST_ASSERT_1(val == MMIO_VAL, val); + GUEST_ASSERT_EQ(val, MMIO_VAL); asm("1:\n\t" ".pushsection .rodata\n\t" @@ -249,7 +254,7 @@ static void guest_code_delete_memory_region(void) "final_rip_end: .quad 1b\n\t" ".popsection"); - GUEST_ASSERT_1(0, 0); + GUEST_ASSERT(0); } static void test_delete_memory_region(void) -- GitLab From 3d9bd831175e898284eb92dadac7049cd055bad6 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:28 -0700 Subject: [PATCH 0717/3445] KVM: selftests: Convert steal_time test to printf style GUEST_ASSERT Convert the steal_time test to use printf-based GUEST_ASERT. Opportunistically use GUEST_ASSERT_EQ() and GUEST_ASSERT_NE() so that the test spits out debug information on failure. Link: https://lore.kernel.org/r/20230729003643.1053367-20-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/steal_time.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/kvm/steal_time.c b/tools/testing/selftests/kvm/steal_time.c index c87f387120736..8649c8545882a 100644 --- a/tools/testing/selftests/kvm/steal_time.c +++ b/tools/testing/selftests/kvm/steal_time.c @@ -4,6 +4,8 @@ * * Copyright (C) 2020, Red Hat, Inc. */ +#define USE_GUEST_ASSERT_PRINTF 1 + #define _GNU_SOURCE #include #include @@ -31,8 +33,8 @@ static uint64_t guest_stolen_time[NR_VCPUS]; static void check_status(struct kvm_steal_time *st) { GUEST_ASSERT(!(READ_ONCE(st->version) & 1)); - GUEST_ASSERT(READ_ONCE(st->flags) == 0); - GUEST_ASSERT(READ_ONCE(st->preempted) == 0); + GUEST_ASSERT_EQ(READ_ONCE(st->flags), 0); + GUEST_ASSERT_EQ(READ_ONCE(st->preempted), 0); } static void guest_code(int cpu) @@ -40,7 +42,7 @@ static void guest_code(int cpu) struct kvm_steal_time *st = st_gva[cpu]; uint32_t version; - GUEST_ASSERT(rdmsr(MSR_KVM_STEAL_TIME) == ((uint64_t)st_gva[cpu] | KVM_MSR_ENABLED)); + GUEST_ASSERT_EQ(rdmsr(MSR_KVM_STEAL_TIME), ((uint64_t)st_gva[cpu] | KVM_MSR_ENABLED)); memset(st, 0, sizeof(*st)); GUEST_SYNC(0); @@ -122,8 +124,8 @@ static int64_t smccc(uint32_t func, uint64_t arg) static void check_status(struct st_time *st) { - GUEST_ASSERT(READ_ONCE(st->rev) == 0); - GUEST_ASSERT(READ_ONCE(st->attr) == 0); + GUEST_ASSERT_EQ(READ_ONCE(st->rev), 0); + GUEST_ASSERT_EQ(READ_ONCE(st->attr), 0); } static void guest_code(int cpu) @@ -132,15 +134,15 @@ static void guest_code(int cpu) int64_t status; status = smccc(SMCCC_ARCH_FEATURES, PV_TIME_FEATURES); - GUEST_ASSERT(status == 0); + GUEST_ASSERT_EQ(status, 0); status = smccc(PV_TIME_FEATURES, PV_TIME_FEATURES); - GUEST_ASSERT(status == 0); + GUEST_ASSERT_EQ(status, 0); status = smccc(PV_TIME_FEATURES, PV_TIME_ST); - GUEST_ASSERT(status == 0); + GUEST_ASSERT_EQ(status, 0); status = smccc(PV_TIME_ST, 0); - GUEST_ASSERT(status != -1); - GUEST_ASSERT(status == (ulong)st_gva[cpu]); + GUEST_ASSERT_NE(status, -1); + GUEST_ASSERT_EQ(status, (ulong)st_gva[cpu]); st = (struct st_time *)status; GUEST_SYNC(0); -- GitLab From 06b651d250e5eea0a1c1fd31fbbc0e0b27f66592 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:29 -0700 Subject: [PATCH 0718/3445] KVM: selftests: Convert x86's CPUID test to printf style GUEST_ASSERT Convert x86's CPUID test to use printf-based GUEST_ASSERT_EQ() so that the test prints out debug information. Note, the test previously used REPORT_GUEST_ASSERT_2(), but that was pointless because none of the guest-side code passed any parameters to the assert. Link: https://lore.kernel.org/r/20230729003643.1053367-21-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/x86_64/cpuid_test.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/cpuid_test.c b/tools/testing/selftests/kvm/x86_64/cpuid_test.c index d3c3aa93f0903..eb1b65ffc0d5e 100644 --- a/tools/testing/selftests/kvm/x86_64/cpuid_test.c +++ b/tools/testing/selftests/kvm/x86_64/cpuid_test.c @@ -4,6 +4,8 @@ * * Generic tests for KVM CPUID set/get ioctls */ +#define USE_GUEST_ASSERT_PRINTF 1 + #include #include #include @@ -35,10 +37,10 @@ static void test_guest_cpuids(struct kvm_cpuid2 *guest_cpuid) guest_cpuid->entries[i].index, &eax, &ebx, &ecx, &edx); - GUEST_ASSERT(eax == guest_cpuid->entries[i].eax && - ebx == guest_cpuid->entries[i].ebx && - ecx == guest_cpuid->entries[i].ecx && - edx == guest_cpuid->entries[i].edx); + GUEST_ASSERT_EQ(eax, guest_cpuid->entries[i].eax); + GUEST_ASSERT_EQ(ebx, guest_cpuid->entries[i].ebx); + GUEST_ASSERT_EQ(ecx, guest_cpuid->entries[i].ecx); + GUEST_ASSERT_EQ(edx, guest_cpuid->entries[i].edx); } } @@ -51,7 +53,7 @@ static void guest_main(struct kvm_cpuid2 *guest_cpuid) GUEST_SYNC(2); - GUEST_ASSERT(this_cpu_property(X86_PROPERTY_MAX_KVM_LEAF) == 0x40000001); + GUEST_ASSERT_EQ(this_cpu_property(X86_PROPERTY_MAX_KVM_LEAF), 0x40000001); GUEST_DONE(); } @@ -116,7 +118,7 @@ static void run_vcpu(struct kvm_vcpu *vcpu, int stage) case UCALL_DONE: return; case UCALL_ABORT: - REPORT_GUEST_ASSERT_2(uc, "values: %#lx, %#lx"); + REPORT_GUEST_ASSERT(uc); default: TEST_ASSERT(false, "Unexpected exit: %s", exit_reason_str(vcpu->run->exit_reason)); -- GitLab From 82cb0ed66d4e5207c53b31a29d9f71af83190ee6 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:30 -0700 Subject: [PATCH 0719/3445] KVM: selftests: Convert the Hyper-V extended hypercalls test to printf asserts Convert x86's Hyper-V extended hypercalls test to use printf-based GUEST_ASSERT_EQ(). Link: https://lore.kernel.org/r/20230729003643.1053367-22-seanjc@google.com Signed-off-by: Sean Christopherson --- .../testing/selftests/kvm/x86_64/hyperv_extended_hypercalls.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_extended_hypercalls.c b/tools/testing/selftests/kvm/x86_64/hyperv_extended_hypercalls.c index 73af44d2167ff..0107d54a1a08e 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_extended_hypercalls.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_extended_hypercalls.c @@ -8,6 +8,7 @@ * Copyright 2022 Google LLC * Author: Vipin Sharma */ +#define USE_GUEST_ASSERT_PRINTF 1 #include "kvm_util.h" #include "processor.h" @@ -84,7 +85,7 @@ int main(void) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - REPORT_GUEST_ASSERT_2(uc, "arg1 = %ld, arg2 = %ld"); + REPORT_GUEST_ASSERT(uc); break; case UCALL_DONE: break; -- GitLab From 8d1d3ce604e54c43228439291db53543da156110 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:31 -0700 Subject: [PATCH 0720/3445] KVM: selftests: Convert the Hyper-V feature test to printf style GUEST_ASSERT Convert x86's Hyper-V feature test to use print-based guest asserts. Opportunistically use the EQ and NE variants in a few places to capture additional information. Link: https://lore.kernel.org/r/20230729003643.1053367-23-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/hyperv_features.c | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_features.c b/tools/testing/selftests/kvm/x86_64/hyperv_features.c index 78606de9385da..41a6beff78c43 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_features.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_features.c @@ -4,6 +4,8 @@ * * Tests for Hyper-V features enablement */ +#define USE_GUEST_ASSERT_PRINTF 1 + #include #include #include @@ -53,16 +55,21 @@ static void guest_msr(struct msr_data *msr) vector = rdmsr_safe(msr->idx, &msr_val); if (msr->fault_expected) - GUEST_ASSERT_3(vector == GP_VECTOR, msr->idx, vector, GP_VECTOR); + __GUEST_ASSERT(vector == GP_VECTOR, + "Expected #GP on %sMSR(0x%x), got vector '0x%x'", + msr->idx, msr->write ? "WR" : "RD", vector); else - GUEST_ASSERT_3(!vector, msr->idx, vector, 0); + __GUEST_ASSERT(!vector, + "Expected success on %sMSR(0x%x), got vector '0x%x'", + msr->idx, msr->write ? "WR" : "RD", vector); if (vector || is_write_only_msr(msr->idx)) goto done; if (msr->write) - GUEST_ASSERT_3(msr_val == msr->write_val, msr->idx, - msr_val, msr->write_val); + __GUEST_ASSERT(!vector, + "WRMSR(0x%x) to '0x%llx', RDMSR read '0x%llx'", + msr->idx, msr->write_val, msr_val); /* Invariant TSC bit appears when TSC invariant control MSR is written to */ if (msr->idx == HV_X64_MSR_TSC_INVARIANT_CONTROL) { @@ -82,7 +89,7 @@ static void guest_hcall(vm_vaddr_t pgs_gpa, struct hcall_data *hcall) u64 res, input, output; uint8_t vector; - GUEST_ASSERT(hcall->control); + GUEST_ASSERT_NE(hcall->control, 0); wrmsr(HV_X64_MSR_GUEST_OS_ID, HYPERV_LINUX_OS_ID); wrmsr(HV_X64_MSR_HYPERCALL, pgs_gpa); @@ -96,10 +103,14 @@ static void guest_hcall(vm_vaddr_t pgs_gpa, struct hcall_data *hcall) vector = __hyperv_hypercall(hcall->control, input, output, &res); if (hcall->ud_expected) { - GUEST_ASSERT_2(vector == UD_VECTOR, hcall->control, vector); + __GUEST_ASSERT(vector == UD_VECTOR, + "Expected #UD for control '%u', got vector '0x%x'", + hcall->control, vector); } else { - GUEST_ASSERT_2(!vector, hcall->control, vector); - GUEST_ASSERT_2(res == hcall->expect, hcall->expect, res); + __GUEST_ASSERT(!vector, + "Expected no exception for control '%u', got vector '0x%x'", + hcall->control, vector); + GUEST_ASSERT_EQ(res, hcall->expect); } GUEST_DONE(); @@ -495,7 +506,7 @@ static void guest_test_msrs_access(void) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - REPORT_GUEST_ASSERT_3(uc, "MSR = %lx, arg1 = %lx, arg2 = %lx"); + REPORT_GUEST_ASSERT(uc); return; case UCALL_DONE: break; @@ -665,7 +676,7 @@ static void guest_test_hcalls_access(void) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - REPORT_GUEST_ASSERT_2(uc, "arg1 = %lx, arg2 = %lx"); + REPORT_GUEST_ASSERT(uc); return; case UCALL_DONE: break; -- GitLab From bf6c760b9df39ebc83245b37ef09ee390ba05e9f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:32 -0700 Subject: [PATCH 0721/3445] KVM: selftests: Convert x86's KVM paravirt test to printf style GUEST_ASSERT Convert x86's KVM paravirtualization test to use the printf-based GUEST_ASSERT_EQ(). Link: https://lore.kernel.org/r/20230729003643.1053367-24-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/x86_64/kvm_pv_test.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c index f774a9e62858f..1c28b77ff3cd2 100644 --- a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c +++ b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c @@ -4,6 +4,8 @@ * * Tests for KVM paravirtual feature disablement */ +#define USE_GUEST_ASSERT_PRINTF 1 + #include #include #include @@ -46,10 +48,10 @@ static void test_msr(struct msr_data *msr) PR_MSR(msr); vector = rdmsr_safe(msr->idx, &ignored); - GUEST_ASSERT_1(vector == GP_VECTOR, vector); + GUEST_ASSERT_EQ(vector, GP_VECTOR); vector = wrmsr_safe(msr->idx, 0); - GUEST_ASSERT_1(vector == GP_VECTOR, vector); + GUEST_ASSERT_EQ(vector, GP_VECTOR); } struct hcall_data { @@ -77,7 +79,7 @@ static void test_hcall(struct hcall_data *hc) PR_HCALL(hc); r = kvm_hypercall(hc->nr, 0, 0, 0, 0); - GUEST_ASSERT(r == -KVM_ENOSYS); + GUEST_ASSERT_EQ(r, -KVM_ENOSYS); } static void guest_main(void) @@ -125,7 +127,7 @@ static void enter_guest(struct kvm_vcpu *vcpu) pr_hcall(&uc); break; case UCALL_ABORT: - REPORT_GUEST_ASSERT_1(uc, "vector = %lu"); + REPORT_GUEST_ASSERT(uc); return; case UCALL_DONE: return; -- GitLab From 0f52e4aaa61400ce68e122b678811777734421ff Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:33 -0700 Subject: [PATCH 0722/3445] KVM: selftests: Convert the MONITOR/MWAIT test to use printf guest asserts Convert x86's MONITOR/MWAIT test to use printf-based guest asserts. Add a macro to handle reporting failures to reduce the amount of copy+paste needed for MONITOR vs. MWAIT. Link: https://lore.kernel.org/r/20230729003643.1053367-25-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/monitor_mwait_test.c | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c index 72812644d7f5e..960fecab37424 100644 --- a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c +++ b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c @@ -1,4 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 +#define USE_GUEST_ASSERT_PRINTF 1 + #include #include #include @@ -16,14 +18,25 @@ enum monitor_mwait_testcases { MWAIT_DISABLED = BIT(2), }; +/* + * If both MWAIT and its quirk are disabled, MONITOR/MWAIT should #UD, in all + * other scenarios KVM should emulate them as nops. + */ +#define GUEST_ASSERT_MONITOR_MWAIT(insn, testcase, vector) \ +do { \ + bool fault_wanted = ((testcase) & MWAIT_QUIRK_DISABLED) && \ + ((testcase) & MWAIT_DISABLED); \ + \ + if (fault_wanted) \ + __GUEST_ASSERT((vector) == UD_VECTOR, \ + "Expected #UD on " insn " for testcase '0x%x', got '0x%x'", vector); \ + else \ + __GUEST_ASSERT(!(vector), \ + "Expected success on " insn " for testcase '0x%x', got '0x%x'", vector); \ +} while (0) + static void guest_monitor_wait(int testcase) { - /* - * If both MWAIT and its quirk are disabled, MONITOR/MWAIT should #UD, - * in all other scenarios KVM should emulate them as nops. - */ - bool fault_wanted = (testcase & MWAIT_QUIRK_DISABLED) && - (testcase & MWAIT_DISABLED); u8 vector; GUEST_SYNC(testcase); @@ -33,16 +46,10 @@ static void guest_monitor_wait(int testcase) * intercept checks, so the inputs for MONITOR and MWAIT must be valid. */ vector = kvm_asm_safe("monitor", "a"(guest_monitor_wait), "c"(0), "d"(0)); - if (fault_wanted) - GUEST_ASSERT_2(vector == UD_VECTOR, testcase, vector); - else - GUEST_ASSERT_2(!vector, testcase, vector); + GUEST_ASSERT_MONITOR_MWAIT("MONITOR", testcase, vector); vector = kvm_asm_safe("mwait", "a"(guest_monitor_wait), "c"(0), "d"(0)); - if (fault_wanted) - GUEST_ASSERT_2(vector == UD_VECTOR, testcase, vector); - else - GUEST_ASSERT_2(!vector, testcase, vector); + GUEST_ASSERT_MONITOR_MWAIT("MWAIT", testcase, vector); } static void guest_code(void) @@ -85,7 +92,7 @@ int main(int argc, char *argv[]) testcase = uc.args[1]; break; case UCALL_ABORT: - REPORT_GUEST_ASSERT_2(uc, "testcase = %lx, vector = %ld"); + REPORT_GUEST_ASSERT(uc); goto done; case UCALL_DONE: goto done; -- GitLab From b13a307ce3c6435c288017d7edf1c6e2827470dc Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:34 -0700 Subject: [PATCH 0723/3445] KVM: selftests: Convert x86's nested exceptions test to printf guest asserts Convert x86's nested exceptions test to printf-based guest asserts, and use REPORT_GUEST_ASSERT() instead of TEST_FAIL() so that output is formatted correctly. Link: https://lore.kernel.org/r/20230729003643.1053367-26-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/x86_64/nested_exceptions_test.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/nested_exceptions_test.c b/tools/testing/selftests/kvm/x86_64/nested_exceptions_test.c index 5f074a6da90cd..4a29f59a76be6 100644 --- a/tools/testing/selftests/kvm/x86_64/nested_exceptions_test.c +++ b/tools/testing/selftests/kvm/x86_64/nested_exceptions_test.c @@ -1,4 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only +#define USE_GUEST_ASSERT_PRINTF 1 + #define _GNU_SOURCE /* for program_invocation_short_name */ #include "test_util.h" @@ -180,9 +182,7 @@ static void assert_ucall_vector(struct kvm_vcpu *vcpu, int vector) "Expected L2 to ask for %d, L2 says it's done", vector); break; case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld (0x%lx != 0x%lx)", - (const char *)uc.args[0], __FILE__, uc.args[1], - uc.args[2], uc.args[3]); + REPORT_GUEST_ASSERT(uc); break; default: TEST_FAIL("Expected L2 to ask for %d, got unexpected ucall %lu", vector, uc.cmd); -- GitLab From 40b319d6b4e109d5e94ac1054d5147624e79088f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:35 -0700 Subject: [PATCH 0724/3445] KVM: selftests: Convert x86's set BSP ID test to printf style guest asserts Convert the set_boot_cpu_id test to use printf-based guest asserts, specifically the EQ and NE variants. Link: https://lore.kernel.org/r/20230729003643.1053367-27-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c index b25d7556b6385..abb3f26d3ce02 100644 --- a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c +++ b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c @@ -4,6 +4,8 @@ * * Copyright (C) 2020, Red Hat, Inc. */ +#define USE_GUEST_ASSERT_PRINTF 1 + #define _GNU_SOURCE /* for program_invocation_name */ #include #include @@ -20,7 +22,7 @@ static void guest_bsp_vcpu(void *arg) { GUEST_SYNC(1); - GUEST_ASSERT(get_bsp_flag() != 0); + GUEST_ASSERT_NE(get_bsp_flag(), 0); GUEST_DONE(); } @@ -29,7 +31,7 @@ static void guest_not_bsp_vcpu(void *arg) { GUEST_SYNC(1); - GUEST_ASSERT(get_bsp_flag() == 0); + GUEST_ASSERT_EQ(get_bsp_flag(), 0); GUEST_DONE(); } @@ -65,7 +67,7 @@ static void run_vcpu(struct kvm_vcpu *vcpu) stage); break; case UCALL_ABORT: - REPORT_GUEST_ASSERT_2(uc, "values: %#lx, %#lx"); + REPORT_GUEST_ASSERT(uc); default: TEST_ASSERT(false, "Unexpected exit: %s", exit_reason_str(vcpu->run->exit_reason)); -- GitLab From a925f799428168e1a849509c0f425673b62e53ad Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:36 -0700 Subject: [PATCH 0725/3445] KVM: selftests: Convert the nSVM software interrupt test to printf guest asserts Convert x86's nested SVM software interrupt injection test to use printf- based guest asserts. Opportunistically use GUEST_ASSERT() and GUEST_FAIL() in a few locations to spit out more debug information. Link: https://lore.kernel.org/r/20230729003643.1053367-28-seanjc@google.com Signed-off-by: Sean Christopherson --- .../kvm/x86_64/svm_nested_soft_inject_test.c | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c index 4e2479716da6e..c908412c57541 100644 --- a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c +++ b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c @@ -8,6 +8,7 @@ * Copyright (C) 2021, Red Hat, Inc. * */ +#define USE_GUEST_ASSERT_PRINTF 1 #include #include @@ -34,13 +35,12 @@ static void l2_guest_code_int(void); static void guest_int_handler(struct ex_regs *regs) { int_fired++; - GUEST_ASSERT_2(regs->rip == (unsigned long)l2_guest_code_int, - regs->rip, (unsigned long)l2_guest_code_int); + GUEST_ASSERT_EQ(regs->rip, (unsigned long)l2_guest_code_int); } static void l2_guest_code_int(void) { - GUEST_ASSERT_1(int_fired == 1, int_fired); + GUEST_ASSERT_EQ(int_fired, 1); /* * Same as the vmmcall() function, but with a ud2 sneaked after the @@ -53,7 +53,7 @@ static void l2_guest_code_int(void) : "rbx", "rdx", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"); - GUEST_ASSERT_1(bp_fired == 1, bp_fired); + GUEST_ASSERT_EQ(bp_fired, 1); hlt(); } @@ -66,9 +66,9 @@ static void guest_nmi_handler(struct ex_regs *regs) if (nmi_stage_get() == 1) { vmmcall(); - GUEST_ASSERT(false); + GUEST_FAIL("Unexpected resume after VMMCALL"); } else { - GUEST_ASSERT_1(nmi_stage_get() == 3, nmi_stage_get()); + GUEST_ASSERT_EQ(nmi_stage_get(), 3); GUEST_DONE(); } } @@ -104,7 +104,8 @@ static void l1_guest_code(struct svm_test_data *svm, uint64_t is_nmi, uint64_t i } run_guest(vmcb, svm->vmcb_gpa); - GUEST_ASSERT_3(vmcb->control.exit_code == SVM_EXIT_VMMCALL, + __GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_VMMCALL, + "Expected VMMCAL #VMEXIT, got '0x%x', info1 = '0x%llx, info2 = '0x%llx'", vmcb->control.exit_code, vmcb->control.exit_info_1, vmcb->control.exit_info_2); @@ -112,7 +113,7 @@ static void l1_guest_code(struct svm_test_data *svm, uint64_t is_nmi, uint64_t i clgi(); x2apic_write_reg(APIC_ICR, APIC_DEST_SELF | APIC_INT_ASSERT | APIC_DM_NMI); - GUEST_ASSERT_1(nmi_stage_get() == 1, nmi_stage_get()); + GUEST_ASSERT_EQ(nmi_stage_get(), 1); nmi_stage_inc(); stgi(); @@ -133,7 +134,8 @@ static void l1_guest_code(struct svm_test_data *svm, uint64_t is_nmi, uint64_t i vmcb->control.next_rip = vmcb->save.rip + 2; run_guest(vmcb, svm->vmcb_gpa); - GUEST_ASSERT_3(vmcb->control.exit_code == SVM_EXIT_HLT, + __GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_HLT, + "Expected HLT #VMEXIT, got '0x%x', info1 = '0x%llx, info2 = '0x%llx'", vmcb->control.exit_code, vmcb->control.exit_info_1, vmcb->control.exit_info_2); @@ -185,7 +187,7 @@ static void run_test(bool is_nmi) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - REPORT_GUEST_ASSERT_3(uc, "vals = 0x%lx 0x%lx 0x%lx"); + REPORT_GUEST_ASSERT(uc); break; /* NOT REACHED */ case UCALL_DONE: -- GitLab From 847ae0795514a15f2845584870750aac4fc5aaee Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:37 -0700 Subject: [PATCH 0726/3445] KVM: selftests: Convert x86's TSC MSRs test to use printf guest asserts Convert x86's TSC MSRs test, and it's liberal use of GUEST_ASSERT_EQ(), to use printf-based guest assert reporting. Link: https://lore.kernel.org/r/20230729003643.1053367-29-seanjc@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c b/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c index 9265965bd2cd3..cf9114f70e1c0 100644 --- a/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c +++ b/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c @@ -4,6 +4,8 @@ * * Copyright (C) 2020, Red Hat, Inc. */ +#define USE_GUEST_ASSERT_PRINTF 1 + #include #include #include "kvm_util.h" @@ -84,7 +86,7 @@ static void run_vcpu(struct kvm_vcpu *vcpu, int stage) ksft_test_result_pass("stage %d passed\n", stage + 1); return; case UCALL_ABORT: - REPORT_GUEST_ASSERT_2(uc, "values: %#lx, %#lx"); + REPORT_GUEST_ASSERT(uc); default: TEST_ASSERT(false, "Unexpected exit: %s", exit_reason_str(vcpu->run->exit_reason)); -- GitLab From 417bfd0c820f17f40572aca37e5134ed329b791f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:38 -0700 Subject: [PATCH 0727/3445] KVM: selftests: Convert the x86 userspace I/O test to printf guest assert Convert x86's userspace I/O test to use printf-based guest asserts. Link: https://lore.kernel.org/r/20230729003643.1053367-30-seanjc@google.com Signed-off-by: Sean Christopherson --- .../testing/selftests/kvm/x86_64/userspace_io_test.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/userspace_io_test.c b/tools/testing/selftests/kvm/x86_64/userspace_io_test.c index 0cb51fa42773b..2c5d2a18d184a 100644 --- a/tools/testing/selftests/kvm/x86_64/userspace_io_test.c +++ b/tools/testing/selftests/kvm/x86_64/userspace_io_test.c @@ -1,4 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 +#define USE_GUEST_ASSERT_PRINTF 1 + #include #include #include @@ -20,8 +22,8 @@ static void guest_ins_port80(uint8_t *buffer, unsigned int count) end = (unsigned long)buffer + 8192; asm volatile("cld; rep; insb" : "+D"(buffer), "+c"(count) : "d"(0x80) : "memory"); - GUEST_ASSERT_1(count == 0, count); - GUEST_ASSERT_2((unsigned long)buffer == end, buffer, end); + GUEST_ASSERT_EQ(count, 0); + GUEST_ASSERT_EQ((unsigned long)buffer, end); } static void guest_code(void) @@ -43,7 +45,9 @@ static void guest_code(void) memset(buffer, 0, sizeof(buffer)); guest_ins_port80(buffer, 8192); for (i = 0; i < 8192; i++) - GUEST_ASSERT_2(buffer[i] == 0xaa, i, buffer[i]); + __GUEST_ASSERT(buffer[i] == 0xaa, + "Expected '0xaa', got '0x%x' at buffer[%u]", + buffer[i], i); GUEST_DONE(); } @@ -91,7 +95,7 @@ int main(int argc, char *argv[]) case UCALL_DONE: break; case UCALL_ABORT: - REPORT_GUEST_ASSERT_2(uc, "argN+1 = 0x%lx, argN+2 = 0x%lx"); + REPORT_GUEST_ASSERT(uc); default: TEST_FAIL("Unknown ucall %lu", uc.cmd); } -- GitLab From 30a6e0b4553dbf2d935d26945788d37ddb234fa7 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:39 -0700 Subject: [PATCH 0728/3445] KVM: selftests: Convert VMX's PMU capabilities test to printf guest asserts Convert x86's VMX PMU capabilities test to use printf-based guest asserts. Opportunstically add a helper to do the WRMSR+assert so as to reduce the amount of copy+paste needed to spit out debug information. Link: https://lore.kernel.org/r/20230729003643.1053367-31-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/vmx_pmu_caps_test.c | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c index 34efd57c2b32f..ba09d5a01c395 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c @@ -10,6 +10,7 @@ * and check it can be retrieved with KVM_GET_MSR, also test * the invalid LBR formats are rejected. */ +#define USE_GUEST_ASSERT_PRINTF 1 #define _GNU_SOURCE /* for program_invocation_short_name */ #include @@ -52,23 +53,24 @@ static const union perf_capabilities format_caps = { .pebs_format = -1, }; +static void guest_test_perf_capabilities_gp(uint64_t val) +{ + uint8_t vector = wrmsr_safe(MSR_IA32_PERF_CAPABILITIES, val); + + __GUEST_ASSERT(vector == GP_VECTOR, + "Expected #GP for value '0x%llx', got vector '0x%x'", + val, vector); +} + static void guest_code(uint64_t current_val) { - uint8_t vector; int i; - vector = wrmsr_safe(MSR_IA32_PERF_CAPABILITIES, current_val); - GUEST_ASSERT_2(vector == GP_VECTOR, current_val, vector); + guest_test_perf_capabilities_gp(current_val); + guest_test_perf_capabilities_gp(0); - vector = wrmsr_safe(MSR_IA32_PERF_CAPABILITIES, 0); - GUEST_ASSERT_2(vector == GP_VECTOR, 0, vector); - - for (i = 0; i < 64; i++) { - vector = wrmsr_safe(MSR_IA32_PERF_CAPABILITIES, - current_val ^ BIT_ULL(i)); - GUEST_ASSERT_2(vector == GP_VECTOR, - current_val ^ BIT_ULL(i), vector); - } + for (i = 0; i < 64; i++) + guest_test_perf_capabilities_gp(current_val ^ BIT_ULL(i)); GUEST_DONE(); } @@ -95,7 +97,7 @@ static void test_guest_wrmsr_perf_capabilities(union perf_capabilities host_cap) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - REPORT_GUEST_ASSERT_2(uc, "val = 0x%lx, vector = %lu"); + REPORT_GUEST_ASSERT(uc); break; case UCALL_DONE: break; -- GitLab From 4e15c38a1aca477d7f99b66b745e811bc95f9420 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:40 -0700 Subject: [PATCH 0729/3445] KVM: selftests: Convert x86's XCR0 test to use printf-based guest asserts Convert x86's XCR0 vs. CPUID test to use printf-based guest asserts. Link: https://lore.kernel.org/r/20230729003643.1053367-32-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/xcr0_cpuid_test.c | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/xcr0_cpuid_test.c b/tools/testing/selftests/kvm/x86_64/xcr0_cpuid_test.c index 905bd5ae4431d..5e82907977209 100644 --- a/tools/testing/selftests/kvm/x86_64/xcr0_cpuid_test.c +++ b/tools/testing/selftests/kvm/x86_64/xcr0_cpuid_test.c @@ -4,6 +4,7 @@ * * Copyright (C) 2022, Google LLC. */ +#define USE_GUEST_ASSERT_PRINTF 1 #include #include @@ -20,13 +21,14 @@ * Assert that architectural dependency rules are satisfied, e.g. that AVX is * supported if and only if SSE is supported. */ -#define ASSERT_XFEATURE_DEPENDENCIES(supported_xcr0, xfeatures, dependencies) \ -do { \ - uint64_t __supported = (supported_xcr0) & ((xfeatures) | (dependencies)); \ - \ - GUEST_ASSERT_3((__supported & (xfeatures)) != (xfeatures) || \ - __supported == ((xfeatures) | (dependencies)), \ - __supported, (xfeatures), (dependencies)); \ +#define ASSERT_XFEATURE_DEPENDENCIES(supported_xcr0, xfeatures, dependencies) \ +do { \ + uint64_t __supported = (supported_xcr0) & ((xfeatures) | (dependencies)); \ + \ + __GUEST_ASSERT((__supported & (xfeatures)) != (xfeatures) || \ + __supported == ((xfeatures) | (dependencies)), \ + "supported = 0x%llx, xfeatures = 0x%llx, dependencies = 0x%llx", \ + __supported, (xfeatures), (dependencies)); \ } while (0) /* @@ -41,7 +43,8 @@ do { \ do { \ uint64_t __supported = (supported_xcr0) & (xfeatures); \ \ - GUEST_ASSERT_2(!__supported || __supported == (xfeatures), \ + __GUEST_ASSERT(!__supported || __supported == (xfeatures), \ + "supported = 0x%llx, xfeatures = 0x%llx", \ __supported, (xfeatures)); \ } while (0) @@ -79,14 +82,18 @@ static void guest_code(void) XFEATURE_MASK_XTILE); vector = xsetbv_safe(0, supported_xcr0); - GUEST_ASSERT_2(!vector, supported_xcr0, vector); + __GUEST_ASSERT(!vector, + "Expected success on XSETBV(0x%llx), got vector '0x%x'", + supported_xcr0, vector); for (i = 0; i < 64; i++) { if (supported_xcr0 & BIT_ULL(i)) continue; vector = xsetbv_safe(0, supported_xcr0 | BIT_ULL(i)); - GUEST_ASSERT_3(vector == GP_VECTOR, supported_xcr0, vector, BIT_ULL(i)); + __GUEST_ASSERT(vector == GP_VECTOR, + "Expected #GP on XSETBV(0x%llx), supported XCR0 = %llx, got vector '0x%x'", + BIT_ULL(i), supported_xcr0, vector); } GUEST_DONE(); @@ -117,7 +124,7 @@ int main(int argc, char *argv[]) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - REPORT_GUEST_ASSERT_3(uc, "0x%lx 0x%lx 0x%lx"); + REPORT_GUEST_ASSERT(uc); break; case UCALL_DONE: goto done; -- GitLab From 7ce7f8e754186f71ba7daffbc99543961a613bba Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:41 -0700 Subject: [PATCH 0730/3445] KVM: selftests: Rip out old, param-based guest assert macros Drop the param-based guest assert macros and enable the printf versions for all selftests. Note! This change can affect tests even if they don't use directly use guest asserts! E.g. via library code, or due to the compiler making different optimization decisions. Link: https://lore.kernel.org/r/20230729003643.1053367-33-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/aarch64/arch_timer.c | 2 - .../selftests/kvm/aarch64/debug-exceptions.c | 2 - .../selftests/kvm/aarch64/hypercalls.c | 2 - .../selftests/kvm/aarch64/page_fault_test.c | 2 - .../testing/selftests/kvm/aarch64/vgic_irq.c | 2 - .../testing/selftests/kvm/guest_print_test.c | 2 - .../selftests/kvm/include/ucall_common.h | 71 ------------------- .../testing/selftests/kvm/memslot_perf_test.c | 2 - tools/testing/selftests/kvm/s390x/memop.c | 2 - tools/testing/selftests/kvm/s390x/tprot.c | 2 - .../selftests/kvm/set_memory_region_test.c | 2 - tools/testing/selftests/kvm/steal_time.c | 2 - .../testing/selftests/kvm/x86_64/cpuid_test.c | 2 - .../kvm/x86_64/hyperv_extended_hypercalls.c | 2 - .../selftests/kvm/x86_64/hyperv_features.c | 2 - .../selftests/kvm/x86_64/kvm_pv_test.c | 2 - .../selftests/kvm/x86_64/monitor_mwait_test.c | 2 - .../kvm/x86_64/nested_exceptions_test.c | 2 - .../selftests/kvm/x86_64/set_boot_cpu_id.c | 2 - .../kvm/x86_64/svm_nested_soft_inject_test.c | 2 - .../selftests/kvm/x86_64/tsc_msrs_test.c | 2 - .../selftests/kvm/x86_64/userspace_io_test.c | 2 - .../selftests/kvm/x86_64/vmx_pmu_caps_test.c | 2 - .../selftests/kvm/x86_64/xcr0_cpuid_test.c | 2 - 24 files changed, 117 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/arch_timer.c b/tools/testing/selftests/kvm/aarch64/arch_timer.c index b53bcf126e6a6..274b8465b42a5 100644 --- a/tools/testing/selftests/kvm/aarch64/arch_timer.c +++ b/tools/testing/selftests/kvm/aarch64/arch_timer.c @@ -19,8 +19,6 @@ * * Copyright (c) 2021, Google LLC. */ -#define USE_GUEST_ASSERT_PRINTF 1 - #define _GNU_SOURCE #include diff --git a/tools/testing/selftests/kvm/aarch64/debug-exceptions.c b/tools/testing/selftests/kvm/aarch64/debug-exceptions.c index fdd5b05e1b0e5..f5b6cb3a00191 100644 --- a/tools/testing/selftests/kvm/aarch64/debug-exceptions.c +++ b/tools/testing/selftests/kvm/aarch64/debug-exceptions.c @@ -1,6 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#define USE_GUEST_ASSERT_PRINTF 1 - #include #include #include diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c index 94555a7d3c7ee..31f66ba97228b 100644 --- a/tools/testing/selftests/kvm/aarch64/hypercalls.c +++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c @@ -8,8 +8,6 @@ * hypercalls are properly masked or unmasked to the guest when disabled or * enabled from the KVM userspace, respectively. */ -#define USE_GUEST_ASSERT_PRINTF 1 - #include #include #include diff --git a/tools/testing/selftests/kvm/aarch64/page_fault_test.c b/tools/testing/selftests/kvm/aarch64/page_fault_test.c index 0b0dd90feae5c..47bb914ab2fa8 100644 --- a/tools/testing/selftests/kvm/aarch64/page_fault_test.c +++ b/tools/testing/selftests/kvm/aarch64/page_fault_test.c @@ -7,8 +7,6 @@ * hugetlbfs with a hole). It checks that the expected handling method is * called (e.g., uffd faults with the right address and write/read flag). */ -#define USE_GUEST_ASSERT_PRINTF 1 - #define _GNU_SOURCE #include #include diff --git a/tools/testing/selftests/kvm/aarch64/vgic_irq.c b/tools/testing/selftests/kvm/aarch64/vgic_irq.c index 67da33aa6d17d..2e64b4856e388 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_irq.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_irq.c @@ -7,8 +7,6 @@ * host to inject a specific intid via a GUEST_SYNC call, and then checks that * it received it. */ -#define USE_GUEST_ASSERT_PRINTF 1 - #include #include #include diff --git a/tools/testing/selftests/kvm/guest_print_test.c b/tools/testing/selftests/kvm/guest_print_test.c index 267e01d057fb4..41230b7461902 100644 --- a/tools/testing/selftests/kvm/guest_print_test.c +++ b/tools/testing/selftests/kvm/guest_print_test.c @@ -4,8 +4,6 @@ * * Copyright 2022, Google, Inc. and/or its affiliates. */ -#define USE_GUEST_ASSERT_PRINTF 1 - #include #include #include diff --git a/tools/testing/selftests/kvm/include/ucall_common.h b/tools/testing/selftests/kvm/include/ucall_common.h index 9e5948dab0304..99bbb56cd1a51 100644 --- a/tools/testing/selftests/kvm/include/ucall_common.h +++ b/tools/testing/selftests/kvm/include/ucall_common.h @@ -66,7 +66,6 @@ enum guest_assert_builtin_args { GUEST_ASSERT_BUILTIN_NARGS }; -#ifdef USE_GUEST_ASSERT_PRINTF #define ____GUEST_ASSERT(_condition, _exp, _fmt, _args...) \ do { \ if (!(_condition)) \ @@ -108,74 +107,4 @@ do { \ #define GUEST_ASSERT_1(_condition, arg1) \ __GUEST_ASSERT(_condition, "arg1 = 0x%lx", arg1) -#else - -#define __GUEST_ASSERT(_condition, _condstr, _nargs, _args...) \ -do { \ - if (!(_condition)) \ - ucall(UCALL_ABORT, GUEST_ASSERT_BUILTIN_NARGS + _nargs, \ - "Failed guest assert: " _condstr, \ - __FILE__, __LINE__, ##_args); \ -} while (0) - -#define GUEST_ASSERT(_condition) \ - __GUEST_ASSERT(_condition, #_condition, 0, 0) - -#define GUEST_ASSERT_1(_condition, arg1) \ - __GUEST_ASSERT(_condition, #_condition, 1, (arg1)) - -#define GUEST_ASSERT_2(_condition, arg1, arg2) \ - __GUEST_ASSERT(_condition, #_condition, 2, (arg1), (arg2)) - -#define GUEST_ASSERT_3(_condition, arg1, arg2, arg3) \ - __GUEST_ASSERT(_condition, #_condition, 3, (arg1), (arg2), (arg3)) - -#define GUEST_ASSERT_4(_condition, arg1, arg2, arg3, arg4) \ - __GUEST_ASSERT(_condition, #_condition, 4, (arg1), (arg2), (arg3), (arg4)) - -#define GUEST_ASSERT_EQ(a, b) __GUEST_ASSERT((a) == (b), #a " == " #b, 2, a, b) - -#define __REPORT_GUEST_ASSERT(_ucall, fmt, _args...) \ - TEST_FAIL("%s at %s:%ld\n" fmt, \ - (const char *)(_ucall).args[GUEST_ERROR_STRING], \ - (const char *)(_ucall).args[GUEST_FILE], \ - (_ucall).args[GUEST_LINE], \ - ##_args) - -#define GUEST_ASSERT_ARG(ucall, i) ((ucall).args[GUEST_ASSERT_BUILTIN_NARGS + i]) - -#define REPORT_GUEST_ASSERT(ucall) \ - __REPORT_GUEST_ASSERT((ucall), "") - -#define REPORT_GUEST_ASSERT_1(ucall, fmt) \ - __REPORT_GUEST_ASSERT((ucall), \ - fmt, \ - GUEST_ASSERT_ARG((ucall), 0)) - -#define REPORT_GUEST_ASSERT_2(ucall, fmt) \ - __REPORT_GUEST_ASSERT((ucall), \ - fmt, \ - GUEST_ASSERT_ARG((ucall), 0), \ - GUEST_ASSERT_ARG((ucall), 1)) - -#define REPORT_GUEST_ASSERT_3(ucall, fmt) \ - __REPORT_GUEST_ASSERT((ucall), \ - fmt, \ - GUEST_ASSERT_ARG((ucall), 0), \ - GUEST_ASSERT_ARG((ucall), 1), \ - GUEST_ASSERT_ARG((ucall), 2)) - -#define REPORT_GUEST_ASSERT_4(ucall, fmt) \ - __REPORT_GUEST_ASSERT((ucall), \ - fmt, \ - GUEST_ASSERT_ARG((ucall), 0), \ - GUEST_ASSERT_ARG((ucall), 1), \ - GUEST_ASSERT_ARG((ucall), 2), \ - GUEST_ASSERT_ARG((ucall), 3)) - -#define REPORT_GUEST_ASSERT_N(ucall, fmt, args...) \ - __REPORT_GUEST_ASSERT((ucall), fmt, ##args) - -#endif /* USE_GUEST_ASSERT_PRINTF */ - #endif /* SELFTEST_KVM_UCALL_COMMON_H */ diff --git a/tools/testing/selftests/kvm/memslot_perf_test.c b/tools/testing/selftests/kvm/memslot_perf_test.c index 55f1bc70e5719..20eb2e730800e 100644 --- a/tools/testing/selftests/kvm/memslot_perf_test.c +++ b/tools/testing/selftests/kvm/memslot_perf_test.c @@ -6,8 +6,6 @@ * * Basic guest setup / host vCPU thread code lifted from set_memory_region_test. */ -#define USE_GUEST_ASSERT_PRINTF 1 - #include #include #include diff --git a/tools/testing/selftests/kvm/s390x/memop.c b/tools/testing/selftests/kvm/s390x/memop.c index a49173907cec2..bb3ca9a5d7318 100644 --- a/tools/testing/selftests/kvm/s390x/memop.c +++ b/tools/testing/selftests/kvm/s390x/memop.c @@ -4,8 +4,6 @@ * * Copyright (C) 2019, Red Hat, Inc. */ -#define USE_GUEST_ASSERT_PRINTF 1 - #include #include #include diff --git a/tools/testing/selftests/kvm/s390x/tprot.c b/tools/testing/selftests/kvm/s390x/tprot.c index c12c6824d9636..c73f948c9b637 100644 --- a/tools/testing/selftests/kvm/s390x/tprot.c +++ b/tools/testing/selftests/kvm/s390x/tprot.c @@ -4,8 +4,6 @@ * * Copyright IBM Corp. 2021 */ -#define USE_GUEST_ASSERT_PRINTF 1 - #include #include "test_util.h" #include "kvm_util.h" diff --git a/tools/testing/selftests/kvm/set_memory_region_test.c b/tools/testing/selftests/kvm/set_memory_region_test.c index dd8f4bac9df8a..b32960189f5f1 100644 --- a/tools/testing/selftests/kvm/set_memory_region_test.c +++ b/tools/testing/selftests/kvm/set_memory_region_test.c @@ -1,6 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#define USE_GUEST_ASSERT_PRINTF 1 - #define _GNU_SOURCE /* for program_invocation_short_name */ #include #include diff --git a/tools/testing/selftests/kvm/steal_time.c b/tools/testing/selftests/kvm/steal_time.c index 8649c8545882a..171adfb2a6cbc 100644 --- a/tools/testing/selftests/kvm/steal_time.c +++ b/tools/testing/selftests/kvm/steal_time.c @@ -4,8 +4,6 @@ * * Copyright (C) 2020, Red Hat, Inc. */ -#define USE_GUEST_ASSERT_PRINTF 1 - #define _GNU_SOURCE #include #include diff --git a/tools/testing/selftests/kvm/x86_64/cpuid_test.c b/tools/testing/selftests/kvm/x86_64/cpuid_test.c index eb1b65ffc0d5e..3b34d8156d1c9 100644 --- a/tools/testing/selftests/kvm/x86_64/cpuid_test.c +++ b/tools/testing/selftests/kvm/x86_64/cpuid_test.c @@ -4,8 +4,6 @@ * * Generic tests for KVM CPUID set/get ioctls */ -#define USE_GUEST_ASSERT_PRINTF 1 - #include #include #include diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_extended_hypercalls.c b/tools/testing/selftests/kvm/x86_64/hyperv_extended_hypercalls.c index 0107d54a1a08e..e036db1f32b9b 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_extended_hypercalls.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_extended_hypercalls.c @@ -8,8 +8,6 @@ * Copyright 2022 Google LLC * Author: Vipin Sharma */ -#define USE_GUEST_ASSERT_PRINTF 1 - #include "kvm_util.h" #include "processor.h" #include "hyperv.h" diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_features.c b/tools/testing/selftests/kvm/x86_64/hyperv_features.c index 41a6beff78c43..9f28aa276c4e2 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_features.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_features.c @@ -4,8 +4,6 @@ * * Tests for Hyper-V features enablement */ -#define USE_GUEST_ASSERT_PRINTF 1 - #include #include #include diff --git a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c index 1c28b77ff3cd2..9e2879af7c201 100644 --- a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c +++ b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c @@ -4,8 +4,6 @@ * * Tests for KVM paravirtual feature disablement */ -#define USE_GUEST_ASSERT_PRINTF 1 - #include #include #include diff --git a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c index 960fecab37424..80aa3d8b18f80 100644 --- a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c +++ b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c @@ -1,6 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#define USE_GUEST_ASSERT_PRINTF 1 - #include #include #include diff --git a/tools/testing/selftests/kvm/x86_64/nested_exceptions_test.c b/tools/testing/selftests/kvm/x86_64/nested_exceptions_test.c index 4a29f59a76be6..3670331adf21a 100644 --- a/tools/testing/selftests/kvm/x86_64/nested_exceptions_test.c +++ b/tools/testing/selftests/kvm/x86_64/nested_exceptions_test.c @@ -1,6 +1,4 @@ // SPDX-License-Identifier: GPL-2.0-only -#define USE_GUEST_ASSERT_PRINTF 1 - #define _GNU_SOURCE /* for program_invocation_short_name */ #include "test_util.h" diff --git a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c index abb3f26d3ce02..366cf18600bc7 100644 --- a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c +++ b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c @@ -4,8 +4,6 @@ * * Copyright (C) 2020, Red Hat, Inc. */ -#define USE_GUEST_ASSERT_PRINTF 1 - #define _GNU_SOURCE /* for program_invocation_name */ #include #include diff --git a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c index c908412c57541..7ee44496cf97f 100644 --- a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c +++ b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c @@ -8,8 +8,6 @@ * Copyright (C) 2021, Red Hat, Inc. * */ -#define USE_GUEST_ASSERT_PRINTF 1 - #include #include #include diff --git a/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c b/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c index cf9114f70e1c0..12b0964f4f131 100644 --- a/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c +++ b/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c @@ -4,8 +4,6 @@ * * Copyright (C) 2020, Red Hat, Inc. */ -#define USE_GUEST_ASSERT_PRINTF 1 - #include #include #include "kvm_util.h" diff --git a/tools/testing/selftests/kvm/x86_64/userspace_io_test.c b/tools/testing/selftests/kvm/x86_64/userspace_io_test.c index 2c5d2a18d184a..255c50b0dc326 100644 --- a/tools/testing/selftests/kvm/x86_64/userspace_io_test.c +++ b/tools/testing/selftests/kvm/x86_64/userspace_io_test.c @@ -1,6 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#define USE_GUEST_ASSERT_PRINTF 1 - #include #include #include diff --git a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c index ba09d5a01c395..ebbcb0a3f7438 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c @@ -10,8 +10,6 @@ * and check it can be retrieved with KVM_GET_MSR, also test * the invalid LBR formats are rejected. */ -#define USE_GUEST_ASSERT_PRINTF 1 - #define _GNU_SOURCE /* for program_invocation_short_name */ #include diff --git a/tools/testing/selftests/kvm/x86_64/xcr0_cpuid_test.c b/tools/testing/selftests/kvm/x86_64/xcr0_cpuid_test.c index 5e82907977209..77d04a7bdaddd 100644 --- a/tools/testing/selftests/kvm/x86_64/xcr0_cpuid_test.c +++ b/tools/testing/selftests/kvm/x86_64/xcr0_cpuid_test.c @@ -4,8 +4,6 @@ * * Copyright (C) 2022, Google LLC. */ -#define USE_GUEST_ASSERT_PRINTF 1 - #include #include #include -- GitLab From 6f321017c84b33a69f6ac131f6c91d1e8a5ff585 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:42 -0700 Subject: [PATCH 0731/3445] KVM: selftests: Print out guest RIP on unhandled exception Use the newfanged printf-based guest assert framework to spit out the guest RIP when an unhandled exception is detected, which makes debugging such failures *much* easier. Link: https://lore.kernel.org/r/20230729003643.1053367-34-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/lib/x86_64/processor.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index d4a0b504b1e0a..d8288374078e4 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -1074,11 +1074,6 @@ static bool kvm_fixup_exception(struct ex_regs *regs) return true; } -void kvm_exit_unexpected_vector(uint32_t value) -{ - ucall(UCALL_UNHANDLED, 1, value); -} - void route_exception(struct ex_regs *regs) { typedef void(*handler)(struct ex_regs *); @@ -1092,7 +1087,10 @@ void route_exception(struct ex_regs *regs) if (kvm_fixup_exception(regs)) return; - kvm_exit_unexpected_vector(regs->vector); + ucall_assert(UCALL_UNHANDLED, + "Unhandled exception in guest", __FILE__, __LINE__, + "Unhandled exception '0x%lx' at guest RIP '0x%lx'", + regs->vector, regs->rip); } void vm_init_descriptor_tables(struct kvm_vm *vm) @@ -1135,12 +1133,8 @@ void assert_on_unhandled_exception(struct kvm_vcpu *vcpu) { struct ucall uc; - if (get_ucall(vcpu, &uc) == UCALL_UNHANDLED) { - uint64_t vector = uc.args[0]; - - TEST_FAIL("Unexpected vectored event in guest (vector:0x%lx)", - vector); - } + if (get_ucall(vcpu, &uc) == UCALL_UNHANDLED) + REPORT_GUEST_ASSERT(uc); } const struct kvm_cpuid_entry2 *get_cpuid_entry(const struct kvm_cpuid2 *cpuid, -- GitLab From a05c4c2bd8b59e291cc9d68b79d6b45a34bcb54e Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 17:36:43 -0700 Subject: [PATCH 0732/3445] KVM: selftests: Use GUEST_FAIL() in ARM's arch timer helpers Use GUEST_FAIL() in ARM's arch timer helpers now that printf-based guest asserts are the default (and only) style of guest asserts, and say goodbye to the GUEST_ASSERT_1() alias. Link: https://lore.kernel.org/r/20230729003643.1053367-35-seanjc@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/include/aarch64/arch_timer.h | 12 ++++++------ tools/testing/selftests/kvm/include/ucall_common.h | 4 ---- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/kvm/include/aarch64/arch_timer.h b/tools/testing/selftests/kvm/include/aarch64/arch_timer.h index cb7c03de3a210..b3e97525cb555 100644 --- a/tools/testing/selftests/kvm/include/aarch64/arch_timer.h +++ b/tools/testing/selftests/kvm/include/aarch64/arch_timer.h @@ -41,7 +41,7 @@ static inline uint64_t timer_get_cntct(enum arch_timer timer) case PHYSICAL: return read_sysreg(cntpct_el0); default: - GUEST_ASSERT_1(0, timer); + GUEST_FAIL("Unexpected timer type = %u", timer); } /* We should not reach here */ @@ -58,7 +58,7 @@ static inline void timer_set_cval(enum arch_timer timer, uint64_t cval) write_sysreg(cval, cntp_cval_el0); break; default: - GUEST_ASSERT_1(0, timer); + GUEST_FAIL("Unexpected timer type = %u", timer); } isb(); @@ -72,7 +72,7 @@ static inline uint64_t timer_get_cval(enum arch_timer timer) case PHYSICAL: return read_sysreg(cntp_cval_el0); default: - GUEST_ASSERT_1(0, timer); + GUEST_FAIL("Unexpected timer type = %u", timer); } /* We should not reach here */ @@ -89,7 +89,7 @@ static inline void timer_set_tval(enum arch_timer timer, uint32_t tval) write_sysreg(tval, cntp_tval_el0); break; default: - GUEST_ASSERT_1(0, timer); + GUEST_FAIL("Unexpected timer type = %u", timer); } isb(); @@ -105,7 +105,7 @@ static inline void timer_set_ctl(enum arch_timer timer, uint32_t ctl) write_sysreg(ctl, cntp_ctl_el0); break; default: - GUEST_ASSERT_1(0, timer); + GUEST_FAIL("Unexpected timer type = %u", timer); } isb(); @@ -119,7 +119,7 @@ static inline uint32_t timer_get_ctl(enum arch_timer timer) case PHYSICAL: return read_sysreg(cntp_ctl_el0); default: - GUEST_ASSERT_1(0, timer); + GUEST_FAIL("Unexpected timer type = %u", timer); } /* We should not reach here */ diff --git a/tools/testing/selftests/kvm/include/ucall_common.h b/tools/testing/selftests/kvm/include/ucall_common.h index 99bbb56cd1a51..112bc1da732a4 100644 --- a/tools/testing/selftests/kvm/include/ucall_common.h +++ b/tools/testing/selftests/kvm/include/ucall_common.h @@ -103,8 +103,4 @@ do { \ (const char *)(ucall).args[GUEST_FILE], \ (ucall).args[GUEST_LINE], "%s", (ucall).buffer) -/* FIXME: Drop this alias once the param-based guest asserts are gone. */ -#define GUEST_ASSERT_1(_condition, arg1) \ - __GUEST_ASSERT(_condition, "arg1 = 0x%lx", arg1) - #endif /* SELFTEST_KVM_UCALL_COMMON_H */ -- GitLab From 7f717f54845c518a64fe5464d855ddeca272483a Mon Sep 17 00:00:00 2001 From: Michal Luczaj Date: Tue, 18 Jul 2023 12:15:44 +0200 Subject: [PATCH 0733/3445] KVM: x86: Remove x86_emulate_ops::guest_has_long_mode Remove x86_emulate_ops::guest_has_long_mode along with its implementation, emulator_guest_has_long_mode(). It has been unused since commit 1d0da94cdafe ("KVM: x86: do not go through ctxt->ops when emulating rsm"). No functional change intended. Signed-off-by: Michal Luczaj Link: https://lore.kernel.org/r/20230718101809.1249769-1-mhal@rbox.co Signed-off-by: Sean Christopherson --- arch/x86/kvm/kvm_emulate.h | 1 - arch/x86/kvm/x86.c | 6 ------ 2 files changed, 7 deletions(-) diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h index ab65f3a47dfde..be7aeb9b8ea3b 100644 --- a/arch/x86/kvm/kvm_emulate.h +++ b/arch/x86/kvm/kvm_emulate.h @@ -213,7 +213,6 @@ struct x86_emulate_ops { bool (*get_cpuid)(struct x86_emulate_ctxt *ctxt, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx, bool exact_only); - bool (*guest_has_long_mode)(struct x86_emulate_ctxt *ctxt); bool (*guest_has_movbe)(struct x86_emulate_ctxt *ctxt); bool (*guest_has_fxsr)(struct x86_emulate_ctxt *ctxt); bool (*guest_has_rdpid)(struct x86_emulate_ctxt *ctxt); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a6b9bea62fb8a..0fca1546e029e 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -8229,11 +8229,6 @@ static bool emulator_get_cpuid(struct x86_emulate_ctxt *ctxt, return kvm_cpuid(emul_to_vcpu(ctxt), eax, ebx, ecx, edx, exact_only); } -static bool emulator_guest_has_long_mode(struct x86_emulate_ctxt *ctxt) -{ - return guest_cpuid_has(emul_to_vcpu(ctxt), X86_FEATURE_LM); -} - static bool emulator_guest_has_movbe(struct x86_emulate_ctxt *ctxt) { return guest_cpuid_has(emul_to_vcpu(ctxt), X86_FEATURE_MOVBE); @@ -8335,7 +8330,6 @@ static const struct x86_emulate_ops emulate_ops = { .fix_hypercall = emulator_fix_hypercall, .intercept = emulator_intercept, .get_cpuid = emulator_get_cpuid, - .guest_has_long_mode = emulator_guest_has_long_mode, .guest_has_movbe = emulator_guest_has_movbe, .guest_has_fxsr = emulator_guest_has_fxsr, .guest_has_rdpid = emulator_guest_has_rdpid, -- GitLab From af8e2ccfa6f101f505add076c1a4d56c718e0d50 Mon Sep 17 00:00:00 2001 From: Takahiro Itazuri Date: Wed, 12 Jul 2023 19:31:36 +0100 Subject: [PATCH 0734/3445] KVM: x86: Advertise host CPUID 0x80000005 in KVM_GET_SUPPORTED_CPUID Advertise CPUID 0x80000005 (L1 cache and TLB info) to userspace so that VMMs that reflect KVM_GET_SUPPORTED_CPUID into KVM_SET_CPUID2 will enumerate sane cache/TLB information to the guest. CPUID 0x80000006 (L2 cache and TLB and L3 cache info) has been returned since commit 43d05de2bee7 ("KVM: pass through CPUID(0x80000006)"). Enumerating both 0x80000005 and 0x80000006 with KVM_GET_SUPPORTED_CPUID is better than reporting one or the other, and 0x80000005 could be helpful for VMM to pass it to KVM_SET_CPUID{,2} for the same reason with 0x80000006. Signed-off-by: Takahiro Itazuri Link: https://lore.kernel.org/all/ZK7NmfKI9xur%2FMop@google.com Link: https://lore.kernel.org/r/20230712183136.85561-1-itazur@amazon.com [sean: add link, massage changelog] Signed-off-by: Sean Christopherson --- arch/x86/kvm/cpuid.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 7f4d13383cf25..ad6566636c22d 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -1151,6 +1151,9 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) cpuid_entry_override(entry, CPUID_8000_0001_EDX); cpuid_entry_override(entry, CPUID_8000_0001_ECX); break; + case 0x80000005: + /* Pass host L1 cache and TLB info. */ + break; case 0x80000006: /* Drop reserved bits, pass host L2 cache and TLB info. */ entry->edx &= ~GENMASK(17, 16); -- GitLab From a2fd5d02bad6d63daaaf4a8bb19c2400387aca61 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 6 Jun 2023 17:43:09 -0700 Subject: [PATCH 0735/3445] KVM: x86: Snapshot host's MSR_IA32_ARCH_CAPABILITIES Snapshot the host's MSR_IA32_ARCH_CAPABILITIES, if it's supported, instead of reading the MSR every time KVM wants to query the host state, e.g. when initializing the default value during vCPU creation. The paths that query ARCH_CAPABILITIES aren't particularly performance sensitive, but creating vCPUs is a frequent enough operation that burning 8 bytes is a good trade-off. Alternatively, KVM could add a field in kvm_caps and thus skip the on-demand calculations entirely, but a pure snapshot isn't possible due to the way KVM handles the l1tf_vmx_mitigation module param. And unlike the other "supported" fields in kvm_caps, KVM doesn't enforce the "supported" value, i.e. KVM treats ARCH_CAPABILITIES like a CPUID leaf and lets userspace advertise whatever it wants. Those problems are solvable, but it's not clear there is real benefit versus snapshotting the host value, and grabbing the host value will allow additional cleanup of KVM's FB_CLEAR_CTRL code. Link: https://lore.kernel.org/all/20230524061634.54141-2-chao.gao@intel.com Cc: Chao Gao Cc: Xiaoyao Li Reviewed-by: Chao Gao Reviewed-by: Xiaoyao Li Link: https://lore.kernel.org/r/20230607004311.1420507-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 22 ++++++---------------- arch/x86/kvm/x86.c | 13 +++++++------ arch/x86/kvm/x86.h | 1 + 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 254f2296e5494..f0ec9acae86c5 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -255,14 +255,9 @@ static int vmx_setup_l1d_flush(enum vmx_l1d_flush_state l1tf) return 0; } - if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES)) { - u64 msr; - - rdmsrl(MSR_IA32_ARCH_CAPABILITIES, msr); - if (msr & ARCH_CAP_SKIP_VMENTRY_L1DFLUSH) { - l1tf_vmx_mitigation = VMENTER_L1D_FLUSH_NOT_REQUIRED; - return 0; - } + if (host_arch_capabilities & ARCH_CAP_SKIP_VMENTRY_L1DFLUSH) { + l1tf_vmx_mitigation = VMENTER_L1D_FLUSH_NOT_REQUIRED; + return 0; } /* If set to auto use the default l1tf mitigation method */ @@ -373,15 +368,10 @@ static int vmentry_l1d_flush_get(char *s, const struct kernel_param *kp) static void vmx_setup_fb_clear_ctrl(void) { - u64 msr; - - if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES) && + if ((host_arch_capabilities & ARCH_CAP_FB_CLEAR_CTRL) && !boot_cpu_has_bug(X86_BUG_MDS) && - !boot_cpu_has_bug(X86_BUG_TAA)) { - rdmsrl(MSR_IA32_ARCH_CAPABILITIES, msr); - if (msr & ARCH_CAP_FB_CLEAR_CTRL) - vmx_fb_clear_ctrl_available = true; - } + !boot_cpu_has_bug(X86_BUG_TAA)) + vmx_fb_clear_ctrl_available = true; } static __always_inline void vmx_disable_fb_clear(struct vcpu_vmx *vmx) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 0fca1546e029e..a1b13d2d1d719 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -237,6 +237,9 @@ EXPORT_SYMBOL_GPL(enable_apicv); u64 __read_mostly host_xss; EXPORT_SYMBOL_GPL(host_xss); +u64 __read_mostly host_arch_capabilities; +EXPORT_SYMBOL_GPL(host_arch_capabilities); + const struct _kvm_stats_desc kvm_vm_stats_desc[] = { KVM_GENERIC_VM_STATS(), STATS_DESC_COUNTER(VM, mmu_shadow_zapped), @@ -1611,12 +1614,7 @@ static bool kvm_is_immutable_feature_msr(u32 msr) static u64 kvm_get_arch_capabilities(void) { - u64 data = 0; - - if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES)) { - rdmsrl(MSR_IA32_ARCH_CAPABILITIES, data); - data &= KVM_SUPPORTED_ARCH_CAP; - } + u64 data = host_arch_capabilities & KVM_SUPPORTED_ARCH_CAP; /* * If nx_huge_pages is enabled, KVM's shadow paging will ensure that @@ -9490,6 +9488,9 @@ static int __kvm_x86_vendor_init(struct kvm_x86_init_ops *ops) kvm_init_pmu_capability(ops->pmu_ops); + if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES)) + rdmsrl(MSR_IA32_ARCH_CAPABILITIES, host_arch_capabilities); + r = ops->hardware_setup(); if (r != 0) goto out_mmu_exit; diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 82e3dafc5453f..1e7be1f6ab299 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -323,6 +323,7 @@ fastpath_t handle_fastpath_set_msr_irqoff(struct kvm_vcpu *vcpu); extern u64 host_xcr0; extern u64 host_xss; +extern u64 host_arch_capabilities; extern struct kvm_caps kvm_caps; -- GitLab From 550ba57faa04042956079b8d09ec0f83bef8817f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 6 Jun 2023 17:43:10 -0700 Subject: [PATCH 0736/3445] KVM: VMX: Drop unnecessary vmx_fb_clear_ctrl_available "cache" Now that KVM snapshots the host's MSR_IA32_ARCH_CAPABILITIES, drop the similar snapshot/cache of whether or not KVM is allowed to manipulate MSR_IA32_MCU_OPT_CTRL.FB_CLEAR_DIS. The motivation for the cache was presumably to avoid the RDMSR, e.g. boot_cpu_has_bug() is quite cheap, and modifying the vCPU's MSR_IA32_ARCH_CAPABILITIES is an infrequent option and a relatively slow path. Cc: Pawan Gupta Reviewed-by: Pawan Gupta Reviewed-by: Xiaoyao Li Link: https://lore.kernel.org/r/20230607004311.1420507-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index f0ec9acae86c5..e6d1ce2d230cb 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -237,9 +237,6 @@ static const struct { #define L1D_CACHE_ORDER 4 static void *vmx_l1d_flush_pages; -/* Control for disabling CPU Fill buffer clear */ -static bool __read_mostly vmx_fb_clear_ctrl_available; - static int vmx_setup_l1d_flush(enum vmx_l1d_flush_state l1tf) { struct page *page; @@ -366,14 +363,6 @@ static int vmentry_l1d_flush_get(char *s, const struct kernel_param *kp) return sysfs_emit(s, "%s\n", vmentry_l1d_param[l1tf_vmx_mitigation].option); } -static void vmx_setup_fb_clear_ctrl(void) -{ - if ((host_arch_capabilities & ARCH_CAP_FB_CLEAR_CTRL) && - !boot_cpu_has_bug(X86_BUG_MDS) && - !boot_cpu_has_bug(X86_BUG_TAA)) - vmx_fb_clear_ctrl_available = true; -} - static __always_inline void vmx_disable_fb_clear(struct vcpu_vmx *vmx) { u64 msr; @@ -399,7 +388,9 @@ static __always_inline void vmx_enable_fb_clear(struct vcpu_vmx *vmx) static void vmx_update_fb_clear_dis(struct kvm_vcpu *vcpu, struct vcpu_vmx *vmx) { - vmx->disable_fb_clear = vmx_fb_clear_ctrl_available; + vmx->disable_fb_clear = (host_arch_capabilities & ARCH_CAP_FB_CLEAR_CTRL) && + !boot_cpu_has_bug(X86_BUG_MDS) && + !boot_cpu_has_bug(X86_BUG_TAA); /* * If guest will not execute VERW, there is no need to set FB_CLEAR_DIS @@ -8626,8 +8617,6 @@ static int __init vmx_init(void) if (r) goto err_l1d_flush; - vmx_setup_fb_clear_ctrl(); - for_each_possible_cpu(cpu) { INIT_LIST_HEAD(&per_cpu(loaded_vmcss_on_cpu, cpu)); -- GitLab From 775bc098657b4996c8537d0eaf9c20138428b699 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 21 Jul 2023 16:38:58 -0700 Subject: [PATCH 0737/3445] KVM: VMX: Drop manual TLB flush when migrating vmcs.APIC_ACCESS_ADDR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the superfluous flush of the current TLB in VMX's handling of migration of the APIC-access page, as a full TLB flush on all vCPUs will have already been performed in response to kvm_unmap_gfn_range() *if* there were SPTEs pointing at the APIC-access page. And if there were no valid SPTEs, then there can't possibly be TLB entries to flush. The extra flush was added by commit fb6c81984313 ("kvm: vmx: Flush TLB when the APIC-access address changes"), with the justification of "because the SDM says so". The SDM said, and still says: As detailed in Section xx.x.x, an access to the APIC-access page might not cause an APIC-access VM exit if software does not properly invalidate information that may be cached from the EPT paging structures. If EPT was in use on a logical processor at one time with EPTP X, it is recommended that software use the INVEPT instruction with the “single-context” INVEPT type and with EPTP X in the INVEPT descriptor before a VM entry on the same logical processor that enables EPT with EPTP X and either (a) the "virtualize APIC accesses" VM- execution control was changed from 0 to 1; or (b) the value of the APIC-access address was changed. But the "recommendation" for (b) is predicated on there actually being a valid EPT translation *and* possible TLB entries for the GPA (or guest VA when using shadow paging). It's possible that a different vCPU has established a mapping for the new page, but the current vCPU can't have entered the guest, i.e. can't have created a TLB entry, between flushing the old mappings and changing its vmcs.APIC_ACCESS_ADDR. kvm_unmap_gfn_range() waits for all vCPUs to ack KVM_REQ_APIC_PAGE_RELOAD, and then flushes remote TLBs (which may or may not also pend a request). Thus the vCPU is guaranteed to update vmcs.APIC_ACCESS_ADDR before re-entering the guest and before it can possibly create new TLB entries. In other words, KVM does flush in this case, it just does so earlier on while handling the page migration. Note, VMX also flushes if the vCPU is migrated to a new pCPU, i.e. if the vCPU is migrated to a pCPU that entered the guest for a different vCPU. Suggested-by: Yu Zhang Cc: Jim Mattson Reviewed-by: Yu Zhang Reviewed-by: Paolo Bonzini Link: https://lore.kernel.org/r/20230721233858.2343941-1-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 0ecf4be2c6af0..3f868826db7db 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -6767,8 +6767,10 @@ static void vmx_set_apic_access_page_addr(struct kvm_vcpu *vcpu) vmcs_write64(APIC_ACCESS_ADDR, pfn_to_hpa(pfn)); read_unlock(&vcpu->kvm->mmu_lock); - vmx_flush_tlb_current(vcpu); - + /* + * No need for a manual TLB flush at this point, KVM has already done a + * flush if there were SPTEs pointing at the previous page. + */ out: /* * Do not pin apic access page in memory, the MMU notifier -- GitLab From d518f8cc10af7a1265595fccf553a3a5f7121e4f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 7 Jun 2023 13:35:17 -0700 Subject: [PATCH 0738/3445] KVM: SVM: Fix dead KVM_BUG() code in LBR MSR virtualization Refactor KVM's handling of LBR MSRs on SVM to avoid a second layer of case statements, and thus eliminate a dead KVM_BUG() call, which (a) will never be hit in the current code base and (b) if a future commit breaks things, will never fire as KVM passes "false" instead "true" or '1' for the KVM_BUG() condition. Reported-by: Michal Luczaj Cc: Yuan Yao Link: https://lore.kernel.org/r/20230607203519.1570167-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/svm.c | 45 +++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 1bc0936bbd514..623916221ff7c 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -980,43 +980,22 @@ static void svm_disable_lbrv(struct kvm_vcpu *vcpu) svm_copy_lbrs(svm->vmcb01.ptr, svm->vmcb); } -static int svm_get_lbr_msr(struct vcpu_svm *svm, u32 index) +static struct vmcb *svm_get_lbr_vmcb(struct vcpu_svm *svm) { /* - * If the LBR virtualization is disabled, the LBR msrs are always - * kept in the vmcb01 to avoid copying them on nested guest entries. - * - * If nested, and the LBR virtualization is enabled/disabled, the msrs - * are moved between the vmcb01 and vmcb02 as needed. + * If LBR virtualization is disabled, the LBR MSRs are always kept in + * vmcb01. If LBR virtualization is enabled and L1 is running VMs of + * its own, the MSRs are moved between vmcb01 and vmcb02 as needed. */ - struct vmcb *vmcb = - (svm->vmcb->control.virt_ext & LBR_CTL_ENABLE_MASK) ? - svm->vmcb : svm->vmcb01.ptr; - - switch (index) { - case MSR_IA32_DEBUGCTLMSR: - return vmcb->save.dbgctl; - case MSR_IA32_LASTBRANCHFROMIP: - return vmcb->save.br_from; - case MSR_IA32_LASTBRANCHTOIP: - return vmcb->save.br_to; - case MSR_IA32_LASTINTFROMIP: - return vmcb->save.last_excp_from; - case MSR_IA32_LASTINTTOIP: - return vmcb->save.last_excp_to; - default: - KVM_BUG(false, svm->vcpu.kvm, - "%s: Unknown MSR 0x%x", __func__, index); - return 0; - } + return svm->vmcb->control.virt_ext & LBR_CTL_ENABLE_MASK ? svm->vmcb : + svm->vmcb01.ptr; } void svm_update_lbrv(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); - bool enable_lbrv = svm_get_lbr_msr(svm, MSR_IA32_DEBUGCTLMSR) & - DEBUGCTLMSR_LBR; + bool enable_lbrv = svm_get_lbr_vmcb(svm)->save.dbgctl & DEBUGCTLMSR_LBR; bool current_enable_lbrv = !!(svm->vmcb->control.virt_ext & LBR_CTL_ENABLE_MASK); @@ -2835,11 +2814,19 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) msr_info->data = svm->tsc_aux; break; case MSR_IA32_DEBUGCTLMSR: + msr_info->data = svm_get_lbr_vmcb(svm)->save.dbgctl; + break; case MSR_IA32_LASTBRANCHFROMIP: + msr_info->data = svm_get_lbr_vmcb(svm)->save.br_from; + break; case MSR_IA32_LASTBRANCHTOIP: + msr_info->data = svm_get_lbr_vmcb(svm)->save.br_to; + break; case MSR_IA32_LASTINTFROMIP: + msr_info->data = svm_get_lbr_vmcb(svm)->save.last_excp_from; + break; case MSR_IA32_LASTINTTOIP: - msr_info->data = svm_get_lbr_msr(svm, msr_info->index); + msr_info->data = svm_get_lbr_vmcb(svm)->save.last_excp_to; break; case MSR_VM_HSAVE_PA: msr_info->data = svm->nested.hsave_msr; -- GitLab From 41dfb5f13ed9101b217e7085e5b5fb07d705e27f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 7 Jun 2023 13:35:18 -0700 Subject: [PATCH 0739/3445] KVM: SVM: Clean up handling of LBR virtualization enabled Clean up the enable_lbrv computation in svm_update_lbrv() to consolidate the logic for computing enable_lbrv into a single statement, and to remove the coding style violations (lack of curly braces on nested if). No functional change intended. Link: https://lore.kernel.org/r/20230607203519.1570167-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/svm.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 623916221ff7c..6fa918b588d23 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -994,15 +994,10 @@ static struct vmcb *svm_get_lbr_vmcb(struct vcpu_svm *svm) void svm_update_lbrv(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); - - bool enable_lbrv = svm_get_lbr_vmcb(svm)->save.dbgctl & DEBUGCTLMSR_LBR; - - bool current_enable_lbrv = !!(svm->vmcb->control.virt_ext & - LBR_CTL_ENABLE_MASK); - - if (unlikely(is_guest_mode(vcpu) && svm->lbrv_enabled)) - if (unlikely(svm->nested.ctl.virt_ext & LBR_CTL_ENABLE_MASK)) - enable_lbrv = true; + bool current_enable_lbrv = svm->vmcb->control.virt_ext & LBR_CTL_ENABLE_MASK; + bool enable_lbrv = (svm_get_lbr_vmcb(svm)->save.dbgctl & DEBUGCTLMSR_LBR) || + (is_guest_mode(vcpu) && svm->lbrv_enabled && + (svm->nested.ctl.virt_ext & LBR_CTL_ENABLE_MASK)); if (enable_lbrv == current_enable_lbrv) return; -- GitLab From a85cd52d720588b0060a0ebac5c7f497ad6bcd86 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 7 Jun 2023 13:35:19 -0700 Subject: [PATCH 0740/3445] KVM: SVM: Use svm_get_lbr_vmcb() helper to handle writes to DEBUGCTL Use the recently introduced svm_get_lbr_vmcb() instead an open coded equivalent to retrieve the target VMCB when emulating writes to MSR_IA32_DEBUGCTLMSR. No functional change intended. Link: https://lore.kernel.org/r/20230607203519.1570167-4-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/svm.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 6fa918b588d23..d76c8a0764f12 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -3052,13 +3052,8 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) if (data & DEBUGCTL_RESERVED_BITS) return 1; - if (svm->vmcb->control.virt_ext & LBR_CTL_ENABLE_MASK) - svm->vmcb->save.dbgctl = data; - else - svm->vmcb01.ptr->save.dbgctl = data; - + svm_get_lbr_vmcb(svm)->save.dbgctl = data; svm_update_lbrv(vcpu); - break; case MSR_VM_HSAVE_PA: /* -- GitLab From 0033fa35491680bce65ff78fb41445f472aa5baa Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 6 Jun 2023 18:02:03 -0700 Subject: [PATCH 0741/3445] KVM: x86/pmu: Use enums instead of hardcoded magic for arch event indices Add "enum intel_pmu_architectural_events" to replace the magic numbers for the (pseudo-)architectural events, and to give a meaningful name to each event so that new readers don't need psychic powers to understand what the code is doing. Cc: Aaron Lewis Cc: Like Xu Reviewed-by: Like Xu Link: https://lore.kernel.org/r/20230607010206.1425277-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/pmu_intel.c | 55 ++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 80c769c58a876..1109cbdedcae4 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -22,23 +22,51 @@ #define MSR_PMC_FULL_WIDTH_BIT (MSR_IA32_PMC0 - MSR_IA32_PERFCTR0) +enum intel_pmu_architectural_events { + /* + * The order of the architectural events matters as support for each + * event is enumerated via CPUID using the index of the event. + */ + INTEL_ARCH_CPU_CYCLES, + INTEL_ARCH_INSTRUCTIONS_RETIRED, + INTEL_ARCH_REFERENCE_CYCLES, + INTEL_ARCH_LLC_REFERENCES, + INTEL_ARCH_LLC_MISSES, + INTEL_ARCH_BRANCHES_RETIRED, + INTEL_ARCH_BRANCHES_MISPREDICTED, + + NR_REAL_INTEL_ARCH_EVENTS, + + /* + * Pseudo-architectural event used to implement IA32_FIXED_CTR2, a.k.a. + * TSC reference cycles. The architectural reference cycles event may + * or may not actually use the TSC as the reference, e.g. might use the + * core crystal clock or the bus clock (yeah, "architectural"). + */ + PSEUDO_ARCH_REFERENCE_CYCLES = NR_REAL_INTEL_ARCH_EVENTS, + NR_INTEL_ARCH_EVENTS, +}; + static struct { u8 eventsel; u8 unit_mask; } const intel_arch_events[] = { - [0] = { 0x3c, 0x00 }, - [1] = { 0xc0, 0x00 }, - [2] = { 0x3c, 0x01 }, - [3] = { 0x2e, 0x4f }, - [4] = { 0x2e, 0x41 }, - [5] = { 0xc4, 0x00 }, - [6] = { 0xc5, 0x00 }, - /* The above index must match CPUID 0x0A.EBX bit vector */ - [7] = { 0x00, 0x03 }, + [INTEL_ARCH_CPU_CYCLES] = { 0x3c, 0x00 }, + [INTEL_ARCH_INSTRUCTIONS_RETIRED] = { 0xc0, 0x00 }, + [INTEL_ARCH_REFERENCE_CYCLES] = { 0x3c, 0x01 }, + [INTEL_ARCH_LLC_REFERENCES] = { 0x2e, 0x4f }, + [INTEL_ARCH_LLC_MISSES] = { 0x2e, 0x41 }, + [INTEL_ARCH_BRANCHES_RETIRED] = { 0xc4, 0x00 }, + [INTEL_ARCH_BRANCHES_MISPREDICTED] = { 0xc5, 0x00 }, + [PSEUDO_ARCH_REFERENCE_CYCLES] = { 0x00, 0x03 }, }; /* mapping between fixed pmc index and intel_arch_events array */ -static int fixed_pmc_events[] = {1, 0, 7}; +static int fixed_pmc_events[] = { + [0] = INTEL_ARCH_INSTRUCTIONS_RETIRED, + [1] = INTEL_ARCH_CPU_CYCLES, + [2] = PSEUDO_ARCH_REFERENCE_CYCLES, +}; static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data) { @@ -80,13 +108,16 @@ static bool intel_hw_event_available(struct kvm_pmc *pmc) u8 unit_mask = (pmc->eventsel & ARCH_PERFMON_EVENTSEL_UMASK) >> 8; int i; - for (i = 0; i < ARRAY_SIZE(intel_arch_events); i++) { + BUILD_BUG_ON(ARRAY_SIZE(intel_arch_events) != NR_INTEL_ARCH_EVENTS); + + for (i = 0; i < NR_INTEL_ARCH_EVENTS; i++) { if (intel_arch_events[i].eventsel != event_select || intel_arch_events[i].unit_mask != unit_mask) continue; /* disable event that reported as not present by cpuid */ - if ((i < 7) && !(pmu->available_event_types & (1 << i))) + if ((i < PSEUDO_ARCH_REFERENCE_CYCLES) && + !(pmu->available_event_types & (1 << i))) return false; break; -- GitLab From bc9658999b3e44cbad964fe9fbab5a25bd4f5ed3 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 6 Jun 2023 18:02:04 -0700 Subject: [PATCH 0742/3445] KVM: x86/pmu: Simplify intel_hw_event_available() Walk only the "real", i.e. non-pseudo, architectural events when checking if a hardware event is available, i.e. isn't disabled by guest CPUID. Skipping pseudo-arch events in the loop body is unnecessarily convoluted, especially now that KVM has enums that delineate between real and pseudo events. Link: https://lore.kernel.org/r/20230607010206.1425277-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/pmu_intel.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 1109cbdedcae4..db23697f31415 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -110,17 +110,16 @@ static bool intel_hw_event_available(struct kvm_pmc *pmc) BUILD_BUG_ON(ARRAY_SIZE(intel_arch_events) != NR_INTEL_ARCH_EVENTS); - for (i = 0; i < NR_INTEL_ARCH_EVENTS; i++) { + /* + * Disallow events reported as unavailable in guest CPUID. Note, this + * doesn't apply to pseudo-architectural events. + */ + for (i = 0; i < NR_REAL_INTEL_ARCH_EVENTS; i++) { if (intel_arch_events[i].eventsel != event_select || intel_arch_events[i].unit_mask != unit_mask) continue; - /* disable event that reported as not present by cpuid */ - if ((i < PSEUDO_ARCH_REFERENCE_CYCLES) && - !(pmu->available_event_types & (1 << i))) - return false; - - break; + return pmu->available_event_types & BIT(i); } return true; -- GitLab From 6d88d0ee5de142921598e5c0041792bbd860913d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 6 Jun 2023 18:02:05 -0700 Subject: [PATCH 0743/3445] KVM: x86/pmu: Require nr fixed_pmc_events to match nr max fixed counters Assert that the number of known fixed_pmc_events matches the max number of fixed counters supported by KVM, and clean up related code. Opportunistically extend setup_fixed_pmc_eventsel()'s use of array_index_nospec() to cover fixed_counters, as nr_arch_fixed_counters is set based on userspace input (but capped using KVM-controlled values). Link: https://lore.kernel.org/r/20230607010206.1425277-4-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/pmu_intel.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index db23697f31415..f2efa0bf7ae8d 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -468,16 +468,17 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) static void setup_fixed_pmc_eventsel(struct kvm_pmu *pmu) { - size_t size = ARRAY_SIZE(fixed_pmc_events); - struct kvm_pmc *pmc; - u32 event; int i; + BUILD_BUG_ON(ARRAY_SIZE(fixed_pmc_events) != KVM_PMC_MAX_FIXED); + for (i = 0; i < pmu->nr_arch_fixed_counters; i++) { - pmc = &pmu->fixed_counters[i]; - event = fixed_pmc_events[array_index_nospec(i, size)]; + int index = array_index_nospec(i, KVM_PMC_MAX_FIXED); + struct kvm_pmc *pmc = &pmu->fixed_counters[index]; + u32 event = fixed_pmc_events[index]; + pmc->eventsel = (intel_arch_events[event].unit_mask << 8) | - intel_arch_events[event].eventsel; + intel_arch_events[event].eventsel; } } @@ -538,10 +539,8 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) if (pmu->version == 1) { pmu->nr_arch_fixed_counters = 0; } else { - pmu->nr_arch_fixed_counters = - min3(ARRAY_SIZE(fixed_pmc_events), - (size_t) edx.split.num_counters_fixed, - (size_t)kvm_pmu_cap.num_counters_fixed); + pmu->nr_arch_fixed_counters = min_t(int, edx.split.num_counters_fixed, + kvm_pmu_cap.num_counters_fixed); edx.split.bit_width_fixed = min_t(int, edx.split.bit_width_fixed, kvm_pmu_cap.bit_width_fixed); pmu->counter_bitmask[KVM_PMC_FIXED] = -- GitLab From 6de2ccc169683bf81feba163834dae7cdebdd826 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 6 Jun 2023 18:02:06 -0700 Subject: [PATCH 0744/3445] KVM: x86/pmu: Move .hw_event_available() check out of PMC filter helper Move the call to kvm_x86_pmu.hw_event_available(), which has nothing to with the userspace PMU filter, out of check_pmu_event_filter() and into its sole caller pmc_event_is_allowed(). pmc_event_is_allowed() didn't exist when commit 7aadaa988c5e ("KVM: x86/pmu: Drop amd_event_mapping[] in the KVM context"), so presumably the motivation for invoking .hw_event_available() from check_pmu_event_filter() was to avoid having to add multiple call sites. Link: https://lore.kernel.org/r/20230607010206.1425277-5-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/pmu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index bf653df861120..edb89b51b3838 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -382,9 +382,6 @@ static bool check_pmu_event_filter(struct kvm_pmc *pmc) struct kvm_x86_pmu_event_filter *filter; struct kvm *kvm = pmc->vcpu->kvm; - if (!static_call(kvm_x86_pmu_hw_event_available)(pmc)) - return false; - filter = srcu_dereference(kvm->arch.pmu_event_filter, &kvm->srcu); if (!filter) return true; @@ -398,6 +395,7 @@ static bool check_pmu_event_filter(struct kvm_pmc *pmc) static bool pmc_event_is_allowed(struct kvm_pmc *pmc) { return pmc_is_globally_enabled(pmc) && pmc_speculative_in_use(pmc) && + static_call(kvm_x86_pmu_hw_event_available)(pmc) && check_pmu_event_filter(pmc); } -- GitLab From 41e90a69a49be2e3467e811ae8fdc17456af1b02 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 2 Jun 2023 16:32:49 -0700 Subject: [PATCH 0745/3445] KVM: x86: Retry APIC optimized map recalc if vCPU is added/enabled Retry the optimized APIC map recalculation if an APIC-enabled vCPU shows up between allocating the map and filling in the map data. Conditionally reschedule before retrying even though the number of vCPUs that can be created is bounded by KVM. Retrying a few thousand times isn't so slow as to be hugely problematic, but it's not blazing fast either. Reset xapic_id_mistach on each retry as a vCPU could change its xAPIC ID between loops, but do NOT reset max_id. The map size also factors in whether or not a vCPU's local APIC is hardware-enabled, i.e. userspace and/or the guest can theoretically keep KVM retrying indefinitely. The only downside is that KVM will allocate more memory than is strictly necessary if the vCPU with the highest x2APIC ID disabled its APIC while the recalculation was in-progress. Refresh kvm->arch.apic_map_dirty to opportunistically change it from DIRTY => UPDATE_IN_PROGRESS to avoid an unnecessary recalc from a different task, i.e. if another task is waiting to attempt an update (which is likely since a retry happens if and only if an update is required). Link: https://lore.kernel.org/r/20230602233250.1014316-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/lapic.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 113ca9661ab21..673880bc0762c 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -376,7 +376,8 @@ void kvm_recalculate_apic_map(struct kvm *kvm) struct kvm_vcpu *vcpu; unsigned long i; u32 max_id = 255; /* enough space for any xAPIC ID */ - bool xapic_id_mismatch = false; + bool xapic_id_mismatch; + int r; /* Read kvm->arch.apic_map_dirty before kvm->arch.apic_map. */ if (atomic_read_acquire(&kvm->arch.apic_map_dirty) == CLEAN) @@ -386,9 +387,14 @@ void kvm_recalculate_apic_map(struct kvm *kvm) "Dirty APIC map without an in-kernel local APIC"); mutex_lock(&kvm->arch.apic_map_lock); + +retry: /* - * Read kvm->arch.apic_map_dirty before kvm->arch.apic_map - * (if clean) or the APIC registers (if dirty). + * Read kvm->arch.apic_map_dirty before kvm->arch.apic_map (if clean) + * or the APIC registers (if dirty). Note, on retry the map may have + * not yet been marked dirty by whatever task changed a vCPU's x2APIC + * ID, i.e. the map may still show up as in-progress. In that case + * this task still needs to retry and complete its calculation. */ if (atomic_cmpxchg_acquire(&kvm->arch.apic_map_dirty, DIRTY, UPDATE_IN_PROGRESS) == CLEAN) { @@ -397,6 +403,15 @@ void kvm_recalculate_apic_map(struct kvm *kvm) return; } + /* + * Reset the mismatch flag between attempts so that KVM does the right + * thing if a vCPU changes its xAPIC ID, but do NOT reset max_id, i.e. + * keep max_id strictly increasing. Disallowing max_id from shrinking + * ensures KVM won't get stuck in an infinite loop, e.g. if the vCPU + * with the highest x2APIC ID is toggling its APIC on and off. + */ + xapic_id_mismatch = false; + kvm_for_each_vcpu(i, vcpu, kvm) if (kvm_apic_present(vcpu)) max_id = max(max_id, kvm_x2apic_id(vcpu->arch.apic)); @@ -415,9 +430,15 @@ void kvm_recalculate_apic_map(struct kvm *kvm) if (!kvm_apic_present(vcpu)) continue; - if (kvm_recalculate_phys_map(new, vcpu, &xapic_id_mismatch)) { + r = kvm_recalculate_phys_map(new, vcpu, &xapic_id_mismatch); + if (r) { kvfree(new); new = NULL; + if (r == -E2BIG) { + cond_resched(); + goto retry; + } + goto out; } -- GitLab From 38313c6d2a02c28162e06753b01bd885caf9386d Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 2 Aug 2023 08:46:26 -0600 Subject: [PATCH 0746/3445] RDMA/irdma: Replace one-element array with flexible-array member One-element and zero-length arrays are deprecated. So, replace one-element array in struct irdma_qvlist_info with flexible-array member. A patch for this was sent a while ago[1]. However, it seems that, at the time, the changes were partially folded[2][3], and the actual flexible-array transformation was omitted. This patch fixes that. The only binary difference seen before/after changes is shown below: | drivers/infiniband/hw/irdma/hw.o | @@ -868,7 +868,7 @@ | drivers/infiniband/hw/irdma/hw.c:484 (discriminator 2) | size += struct_size(iw_qvlist, qv_info, rf->msix_count); | 55b: imul $0x45c,%rdi,%rdi |- 562: add $0x10,%rdi |+ 562: add $0x4,%rdi which is, of course, expected as it reflects the mistake made while folding the patch I've mentioned above. Worth mentioning is the fact that with this change we save 12 bytes of memory, as can be inferred from the diff snapshot above. Notice that: $ pahole -C rdma_qv_info idrivers/infiniband/hw/irdma/hw.o struct irdma_qv_info { u32 v_idx; /* 0 4 */ u16 ceq_idx; /* 4 2 */ u16 aeq_idx; /* 6 2 */ u8 itr_idx; /* 8 1 */ /* size: 12, cachelines: 1, members: 4 */ /* padding: 3 */ /* last cacheline: 12 bytes */ }; Link: https://lore.kernel.org/linux-hardening/20210525230038.GA175516@embeddedor/ [1] Link: https://lore.kernel.org/linux-hardening/bf46b428deef4e9e89b0ea1704b1f0e5@intel.com/ [2] Link: https://lore.kernel.org/linux-rdma/20210520143809.819-1-shiraz.saleem@intel.com/T/#u [3] Fixes: 44d9e52977a1 ("RDMA/irdma: Implement device initialization definitions") Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/ZMpsQrZadBaJGkt4@work Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/irdma/main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/irdma/main.h b/drivers/infiniband/hw/irdma/main.h index ad2239aabbc59..282cd492fe9b5 100644 --- a/drivers/infiniband/hw/irdma/main.h +++ b/drivers/infiniband/hw/irdma/main.h @@ -239,7 +239,7 @@ struct irdma_qv_info { struct irdma_qvlist_info { u32 num_vectors; - struct irdma_qv_info qv_info[1]; + struct irdma_qv_info qv_info[]; }; struct irdma_gen_ops { -- GitLab From a9b451509565d40a5ca3b41c39a2b758cdbc5355 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 31 Jul 2023 16:19:21 -0300 Subject: [PATCH 0747/3445] tools build: Add 3-component logical version comparators The next cset needs to compare if a flex version is greater or equal/less than another, but since there is no canonical, generally available way to compare versions in the command line (sort -V, yeah, but...), just use awk to canonicalize the versions like is also done in scripts/rust_is_available.sh. There was a problem spotted in linux-next where a bashism, here documents, aka the '<<<' stdin redirector, for strings to be used as the stdin for awk. Use $(shell echo | awk ...) instead. Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/scripts/utilities.mak | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tools/scripts/utilities.mak b/tools/scripts/utilities.mak index 172e47273b5d9..d69d0345cc23f 100644 --- a/tools/scripts/utilities.mak +++ b/tools/scripts/utilities.mak @@ -177,3 +177,23 @@ $(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2))) endef _ge_attempt = $(or $(get-executable),$(call _gea_err,$(2))) _gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) + +# version-ge3 +# +# Usage $(call version-ge3,2.6.4,$(FLEX_VERSION)) +# +# To compare if a 3 component version is greater or equal to another, first use +# was to check the flex version to see if we can use compiler warnings as +# errors for one of the cases flex generates code C compilers complains about. + +version-ge3 = $(shell echo "$(1).$(2)" | awk -F'.' '{ printf("%d\n", (10000000 * $$1 + 10000 * $$2 + $$3) >= (10000000 * $$4 + 10000 * $$5 + $$6)) }') + +# version-lt3 +# +# Usage $(call version-lt3,2.6.2,$(FLEX_VERSION)) +# +# To compare if a 3 component version is less thjan another, first use was to +# check the flex version to see if we can use compiler warnings as errors for +# one of the cases flex generates code C compilers complains about. + +version-lt3 = $(shell echo "$(1).$(2)" | awk -F'.' '{ printf("%d\n", (10000000 * $$1 + 10000 * $$2 + $$3) < (10000000 * $$4 + 10000 * $$5 + $$6)) }') -- GitLab From 10c775afa5992d55be76fa40a6373a93751ba6b4 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 27 Jul 2023 23:49:15 -0700 Subject: [PATCH 0748/3445] perf build: Disable fewer flex warnings If flex is version 2.6.4, reduce the number of flex C warnings disabled. Earlier flex versions have all C warnings disabled. Committer notes: Added this to the list of ignored warnings to get it building on a Fedora 36 machine with flex 2.6.4: -Wno-misleading-indentation Noticed when building with: $ make LLVM=1 -C tools/perf NO_BPF_SKEL=1 DEBUG=1 Take two: We can't just try to canonicalize flex versions by just removing the dots, as we end up with: 2.6.4 >= 2.5.37 becoming: 264 >= 2537 Failing the build on flex 2.5.37, so instead use the back to the past added $(call version_ge3,$(FLEX_VERSION),2.6.4) variant to check for that. Making sure $(FLEX_VERSION) keeps the dots as we may want to use 'sort -V' or something nicer when available everywhere. Some other tweaks for other flex versions and combinations with gcc and clang versions were added, notes on the patch. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andrii Nakryiko Cc: Eduard Zingerman Cc: Gaosheng Cui Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Nick Desaulniers Cc: Peter Zijlstra Cc: Rob Herring Cc: Tom Rix Cc: bpf@vger.kernel.org Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230728064917.767761-5-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/Build | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/Build b/tools/perf/util/Build index bb08149179e40..15c69decb76b5 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -1,3 +1,5 @@ +include $(srctree)/tools/scripts/utilities.mak + perf-y += arm64-frame-pointer-unwind-support.o perf-y += addr_location.o perf-y += annotate.o @@ -279,16 +281,26 @@ $(OUTPUT)util/bpf-filter-bison.c $(OUTPUT)util/bpf-filter-bison.h: util/bpf-filt $(Q)$(call echo-cmd,bison)$(BISON) -v $< -d $(PARSER_DEBUG_BISON) $(BISON_FILE_PREFIX_MAP) \ -o $(OUTPUT)util/bpf-filter-bison.c -p perf_bpf_filter_ -FLEX_GE_26 := $(shell expr $(shell $(FLEX) --version | sed -e 's/flex \([0-9]\+\).\([0-9]\+\)/\1\2/g') \>\= 26) -ifeq ($(FLEX_GE_26),1) - flex_flags := -Wno-switch-enum -Wno-switch-default -Wno-unused-function -Wno-redundant-decls -Wno-sign-compare -Wno-unused-parameter -Wno-missing-prototypes -Wno-missing-declarations - CC_HASNT_MISLEADING_INDENTATION := $(shell echo "int main(void) { return 0 }" | $(CC) -Werror -Wno-misleading-indentation -o /dev/null -xc - 2>&1 | grep -q -- -Wno-misleading-indentation ; echo $$?) - ifeq ($(CC_HASNT_MISLEADING_INDENTATION), 1) - flex_flags += -Wno-misleading-indentation +FLEX_VERSION := $(shell $(FLEX) --version | cut -d' ' -f2) + +FLEX_GE_260 := $(call version-ge3,$(FLEX_VERSION),2.6.0) +ifeq ($(FLEX_GE_260),1) + flex_flags := -Wno-redundant-decls -Wno-switch-default -Wno-unused-function -Wno-misleading-indentation + + # Some newer clang and gcc version complain about this + # util/parse-events-bison.c:1317:9: error: variable 'parse_events_nerrs' set but not used [-Werror,-Wunused-but-set-variable] + # int yynerrs = 0; + + flex_flags += -Wno-unused-but-set-variable + + FLEX_LT_262 := $(call version-lt3,$(FLEX_VERSION),2.6.2) + ifeq ($(FLEX_LT_262),1) + flex_flags += -Wno-sign-compare endif else flex_flags := -w endif + CFLAGS_parse-events-flex.o += $(flex_flags) CFLAGS_pmu-flex.o += $(flex_flags) CFLAGS_expr-flex.o += $(flex_flags) -- GitLab From ddc8e4c966923ad1137790817157c8a5f0301aec Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 27 Jul 2023 23:49:16 -0700 Subject: [PATCH 0749/3445] perf build: Disable fewer bison warnings If bison is version 3.8.2, reduce the number of bison C warnings disabled. Earlier bison versions have all C warnings disabled. Avoid implicit declarations of yylex by adding the declaration in the C file. A header can't be included as a circular dependency would occur due to the lexer using the bison defined tokens. Committer notes: Some recent versions of gcc and clang (noticed on Alpine Linux 3.17, edge, clearlinux, fedora 37, etc. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andrii Nakryiko Cc: Eduard Zingerman Cc: Gaosheng Cui Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Nick Desaulniers Cc: Peter Zijlstra Cc: Rob Herring Cc: Tom Rix Cc: bpf@vger.kernel.org Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230728064917.767761-6-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/Build | 12 ++++++++---- tools/perf/util/bpf-filter.y | 2 ++ tools/perf/util/expr.y | 4 +++- tools/perf/util/parse-events.y | 1 + tools/perf/util/pmu.y | 3 +++ 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 15c69decb76b5..1acfbbd1f39a5 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -306,10 +306,14 @@ CFLAGS_pmu-flex.o += $(flex_flags) CFLAGS_expr-flex.o += $(flex_flags) CFLAGS_bpf-filter-flex.o += $(flex_flags) -bison_flags := -DYYENABLE_NLS=0 -BISON_GE_35 := $(shell expr $(shell $(BISON) --version | grep bison | sed -e 's/.\+ \([0-9]\+\).\([0-9]\+\)/\1\2/g') \>\= 35) -ifeq ($(BISON_GE_35),1) - bison_flags += -Wno-unused-parameter -Wno-nested-externs -Wno-implicit-function-declaration -Wno-switch-enum -Wno-unused-but-set-variable -Wno-unknown-warning-option +# Some newer clang and gcc version complain about this +# util/parse-events-bison.c:1317:9: error: variable 'parse_events_nerrs' set but not used [-Werror,-Wunused-but-set-variable] +# int yynerrs = 0; + +bison_flags := -DYYENABLE_NLS=0 -Wno-unused-but-set-variable +BISON_GE_382 := $(shell expr $(shell $(BISON) --version | grep bison | sed -e 's/.\+ \([0-9]\+\).\([0-9]\+\).\([0-9]\+\)/\1\2\3/g') \>\= 382) +ifeq ($(BISON_GE_382),1) + bison_flags += -Wno-switch-enum else bison_flags += -w endif diff --git a/tools/perf/util/bpf-filter.y b/tools/perf/util/bpf-filter.y index 07d6c7926c13a..5dfa948fc986c 100644 --- a/tools/perf/util/bpf-filter.y +++ b/tools/perf/util/bpf-filter.y @@ -9,6 +9,8 @@ #include #include "bpf-filter.h" +int perf_bpf_filter_lex(void); + static void perf_bpf_filter_error(struct list_head *expr __maybe_unused, char const *msg) { diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y index dd504afd8f368..65d54a6f29ad1 100644 --- a/tools/perf/util/expr.y +++ b/tools/perf/util/expr.y @@ -7,6 +7,8 @@ #include "util/debug.h" #define IN_EXPR_Y 1 #include "expr.h" +#include "expr-bison.h" +int expr_lex(YYSTYPE * yylval_param , void *yyscanner); %} %define api.pure full @@ -56,7 +58,7 @@ static void expr_error(double *final_val __maybe_unused, struct expr_parse_ctx *ctx __maybe_unused, bool compute_ids __maybe_unused, - void *scanner, + void *scanner __maybe_unused, const char *s) { pr_debug("%s\n", s); diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 454577f7aff67..251b7d2fde325 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -20,6 +20,7 @@ #include "parse-events.h" #include "parse-events-bison.h" +int parse_events_lex(YYSTYPE * yylval_param, YYLTYPE * yylloc_param , void *yyscanner); void parse_events_error(YYLTYPE *loc, void *parse_state, void *scanner, char const *msg); #define PE_ABORT(val) \ diff --git a/tools/perf/util/pmu.y b/tools/perf/util/pmu.y index dff4e892ac4d8..3d46cca3bb94c 100644 --- a/tools/perf/util/pmu.y +++ b/tools/perf/util/pmu.y @@ -11,6 +11,9 @@ #include #include #include "pmu.h" +#include "pmu-bison.h" + +int perf_pmu_lex(YYSTYPE * yylval_param , void *yyscanner); #define ABORT_ON(val) \ do { \ -- GitLab From f776b0435e8cf6e73359d4203c2bc7bf2cf4b2af Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 27 Jul 2023 23:49:17 -0700 Subject: [PATCH 0750/3445] perf build: Remove -Wno-redundant-decls in 2 cases Properly fix a warning and remove the -Wno-redundant-decls C flag. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andrii Nakryiko Cc: Eduard Zingerman Cc: Gaosheng Cui Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Nick Desaulniers Cc: Peter Zijlstra Cc: Rob Herring Cc: Tom Rix Cc: bpf@vger.kernel.org Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230728064917.767761-7-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/Build | 2 -- tools/perf/util/parse-events.c | 1 - 2 files changed, 3 deletions(-) diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 1acfbbd1f39a5..d487aec0b458a 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -338,8 +338,6 @@ CFLAGS_find_bit.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ET CFLAGS_rbtree.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" CFLAGS_libstring.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" CFLAGS_hweight.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" -CFLAGS_parse-events.o += -Wno-redundant-decls -CFLAGS_expr.o += -Wno-redundant-decls CFLAGS_header.o += -include $(OUTPUT)PERF-VERSION-FILE CFLAGS_arm-spe.o += -I$(srctree)/tools/arch/arm64/include/ diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 926d3ac97324c..ac315e1be2bcd 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -35,7 +35,6 @@ #ifdef PARSER_DEBUG extern int parse_events_debug; #endif -int parse_events_parse(void *parse_state, void *scanner); static int get_config_terms(struct list_head *head_config, struct list_head *head_terms __maybe_unused); -- GitLab From 7822a8913f4c51c7d1aff793b525d60c3384fb5b Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 27 Jul 2023 19:24:46 -0700 Subject: [PATCH 0751/3445] perf build: Update build rule for generated files The bison and flex generate C files from the source (.y and .l) files. When O= option is used, they are saved in a separate directory but the default build rule assumes the .C files are in the source directory. So it might read invalid file if there are generated files from an old version. The same is true for the pmu-events files. For example, the following command would cause a build failure: $ git checkout v6.3 $ make -C tools/perf # build in the same directory $ git checkout v6.5-rc2 $ mkdir build # create a build directory $ make -C tools/perf O=build # build in a different directory but it # refers files in the source directory Let's update the build rule to specify those cases explicitly to depend on the files in the output directory. Note that it's not a complete fix and it needs the next patch for the include path too. Fixes: 80eeb67fe577aa76 ("perf jevents: Program to convert JSON file") Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Andi Kleen Cc: Anup Sharma Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Peter Zijlstra Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20230728022447.1323563-1-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/Makefile.build | 10 ++++++++++ tools/perf/pmu-events/Build | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/tools/build/Makefile.build b/tools/build/Makefile.build index 89430338a3d92..fac42486a8cf0 100644 --- a/tools/build/Makefile.build +++ b/tools/build/Makefile.build @@ -117,6 +117,16 @@ $(OUTPUT)%.s: %.c FORCE $(call rule_mkdir) $(call if_changed_dep,cc_s_c) +# bison and flex files are generated in the OUTPUT directory +# so it needs a separate rule to depend on them properly +$(OUTPUT)%-bison.o: $(OUTPUT)%-bison.c FORCE + $(call rule_mkdir) + $(call if_changed_dep,$(host)cc_o_c) + +$(OUTPUT)%-flex.o: $(OUTPUT)%-flex.c FORCE + $(call rule_mkdir) + $(call if_changed_dep,$(host)cc_o_c) + # Gather build data: # obj-y - list of build objects # subdir-y - list of directories to nest diff --git a/tools/perf/pmu-events/Build b/tools/perf/pmu-events/Build index 150765f2baeea..1d18bb89402e6 100644 --- a/tools/perf/pmu-events/Build +++ b/tools/perf/pmu-events/Build @@ -35,3 +35,9 @@ $(PMU_EVENTS_C): $(JSON) $(JSON_TEST) $(JEVENTS_PY) $(METRIC_PY) $(METRIC_TEST_L $(call rule_mkdir) $(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(JEVENTS_ARCH) $(JEVENTS_MODEL) pmu-events/arch $@ endif + +# pmu-events.c file is generated in the OUTPUT directory so it needs a +# separate rule to depend on it properly +$(OUTPUT)pmu-events/pmu-events.o: $(PMU_EVENTS_C) + $(call rule_mkdir) + $(call if_changed_dep,cc_o_c) -- GitLab From c7e97f215a4ad634b746804679f5937d25f77e29 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 27 Jul 2023 19:24:47 -0700 Subject: [PATCH 0752/3445] perf build: Include generated header files properly The flex and bison generate header files from the source. When user specified a build directory with O= option, it'd generate files under the directory. The build command has -I option to specify the header include directory. But the -I option only affects the files included like <...>. Let's change the flex and bison headers to use it instead of "...". Fixes: 80eeb67fe577aa76 ("perf jevents: Program to convert JSON file") Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Andi Kleen Cc: Anup Sharma Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Peter Zijlstra Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20230728022447.1323563-2-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/jevents.py | 2 +- tools/perf/util/bpf-filter.c | 4 ++-- tools/perf/util/expr.c | 4 ++-- tools/perf/util/parse-events.c | 4 ++-- tools/perf/util/pmu.c | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py index 08ec9aa583e73..8cd561aa606a2 100755 --- a/tools/perf/pmu-events/jevents.py +++ b/tools/perf/pmu-events/jevents.py @@ -1000,7 +1000,7 @@ such as "arm/cortex-a34".''', _args = ap.parse_args() _args.output_file.write(""" -#include "pmu-events/pmu-events.h" +#include #include "util/header.h" #include "util/pmu.h" #include diff --git a/tools/perf/util/bpf-filter.c b/tools/perf/util/bpf-filter.c index 0b30688d78a7f..47f01df658d9a 100644 --- a/tools/perf/util/bpf-filter.c +++ b/tools/perf/util/bpf-filter.c @@ -9,8 +9,8 @@ #include "util/evsel.h" #include "util/bpf-filter.h" -#include "util/bpf-filter-flex.h" -#include "util/bpf-filter-bison.h" +#include +#include #include "bpf_skel/sample-filter.h" #include "bpf_skel/sample_filter.skel.h" diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c index 4814262e3805c..7410a165f68b7 100644 --- a/tools/perf/util/expr.c +++ b/tools/perf/util/expr.c @@ -10,8 +10,8 @@ #include "debug.h" #include "evlist.h" #include "expr.h" -#include "expr-bison.h" -#include "expr-flex.h" +#include +#include #include "util/hashmap.h" #include "smt.h" #include "tsc.h" diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index ac315e1be2bcd..acddb2542b1a3 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -18,8 +18,8 @@ #include "debug.h" #include #include -#include "parse-events-bison.h" -#include "parse-events-flex.h" +#include +#include #include "pmu.h" #include "pmus.h" #include "asm/bug.h" diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 7f984a7f16ca2..b6654b9f55d22 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -19,8 +19,8 @@ #include "evsel.h" #include "pmu.h" #include "pmus.h" -#include "pmu-bison.h" -#include "pmu-flex.h" +#include +#include #include "parse-events.h" #include "print-events.h" #include "header.h" -- GitLab From c76a1444c00ea6900a5e7d10065d6e93b0e104f9 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 27 Jul 2023 17:12:10 -0700 Subject: [PATCH 0753/3445] perf parse-event: Avoid BPF test SEGV loc is passed as NULL in tools/perf/tests/bpf.c do_test, meaning errors trigger a SEGV when trying to access. Add the missing NULL check. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Eduard Zingerman Cc: He Kuang Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Rob Herring Cc: Wang Nan Cc: Wang ShaoBo Cc: YueHaibing Cc: bpf@vger.kernel.org Link: https://lore.kernel.org/r/20230728001212.457900-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index acddb2542b1a3..e17e96b4f7986 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -757,7 +757,7 @@ int parse_events_load_bpf_obj(struct parse_events_state *parse_state, return 0; errout: - parse_events_error__handle(parse_state->error, param.loc->first_column, + parse_events_error__handle(parse_state->error, param.loc ? param.loc->first_column : 0, strdup(errbuf), strdup("(add -v to see detail)")); return err; } -- GitLab From 30f4ade33d649aa0e8603386721f184ad9d3cb55 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 27 Jul 2023 17:12:11 -0700 Subject: [PATCH 0754/3445] perf tools: Revert enable indices setting syntax for BPF map This reverts commit e571e029bdbf ("perf tools: Enable indices setting syntax for BPF map"). The reverted commit added a notion of arrays that could be set as event terms for BPF events. The parsing hasn't worked over multiple Linux releases. Given the broken nature of the parsing it appears the code isn't in use, nor could I find a way for it to be used to add a test. The original commit contains a test in the commit message, however, running it yields: ``` $ perf record -e './test_bpf_map_3.c/map:channel.value[0,1,2,3...5]=101/' usleep 2 event syntax error: '..pf_map_3.c/map:channel.value[0,1,2,3...5]=101/' \___ parser error Run 'perf list' for a list of valid events Usage: perf record [] [] or: perf record [] -- [] -e, --event event selector. use 'perf list' to list available events ``` Given the code can't be used this commit reverts and removes it. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Eduard Zingerman Cc: He Kuang Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Rob Herring Cc: Wang Nan Cc: Wang ShaoBo Cc: YueHaibing Cc: bpf@vger.kernel.org Link: https://lore.kernel.org/r/20230728001212.457900-3-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 8 +-- tools/perf/util/parse-events.l | 11 --- tools/perf/util/parse-events.y | 122 --------------------------------- 3 files changed, 1 insertion(+), 140 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index e17e96b4f7986..37614dc1d6982 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -799,13 +799,7 @@ parse_events_config_bpf(struct parse_events_state *parse_state, parse_events_error__handle(parse_state->error, idx, strdup(errbuf), - strdup( -"Hint:\tValid config terms:\n" -" \tmap:[].value=[value]\n" -" \tmap:[].event=[event]\n" -"\n" -" \twhere is something like [0,3...5] or [all]\n" -" \t(add -v to see detail)")); + NULL); return err; } } diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 99335ec586ae8..d7d084cc4140d 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -175,7 +175,6 @@ do { \ %x mem %s config %x event -%x array group [^,{}/]*[{][^}]*[}][^,{}/]* event_pmu [^,{}/]+[/][^/]*[/][^,{}/]* @@ -251,14 +250,6 @@ non_digit [^0-9] } } -{ -"]" { BEGIN(config); return ']'; } -{num_dec} { return value(yyscanner, 10); } -{num_hex} { return value(yyscanner, 16); } -, { return ','; } -"\.\.\." { return PE_ARRAY_RANGE; } -} - { /* * Please update config_term_names when new static term is added. @@ -302,8 +293,6 @@ r0x{num_raw_hex} { return str(yyscanner, PE_RAW); } {lc_type}-{lc_op_result} { return lc_str(yyscanner, _parse_state); } {lc_type}-{lc_op_result}-{lc_op_result} { return lc_str(yyscanner, _parse_state); } {name_minus} { return str(yyscanner, PE_NAME); } -\[all\] { return PE_ARRAY_ALL; } -"[" { BEGIN(array); return '['; } @{drv_cfg_term} { return drv_str(yyscanner, PE_DRV_CFG_TERM); } } diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 251b7d2fde325..c3517e3498d7b 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -65,7 +65,6 @@ static void free_list_evsel(struct list_head* list_evsel) %token PE_LEGACY_CACHE %token PE_PREFIX_MEM %token PE_ERROR -%token PE_ARRAY_ALL PE_ARRAY_RANGE %token PE_DRV_CFG_TERM %token PE_TERM_HW %type PE_VALUE @@ -109,11 +108,6 @@ static void free_list_evsel(struct list_head* list_evsel) %type groups %destructor { free_list_evsel ($$); } %type tracepoint_name -%destructor { free ($$.sys); free ($$.event); } -%type array -%type array_term -%type array_terms -%destructor { free ($$.ranges); } %type PE_TERM_HW %destructor { free ($$.str); } @@ -128,7 +122,6 @@ static void free_list_evsel(struct list_head* list_evsel) char *sys; char *event; } tracepoint_name; - struct parse_events_array array; struct hardware_term { char *str; u64 num; @@ -879,121 +872,6 @@ PE_TERM $$ = term; } -| -name_or_raw array '=' name_or_legacy -{ - struct parse_events_term *term; - int err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER, $1, $4, &@1, &@4); - - if (err) { - free($1); - free($4); - free($2.ranges); - PE_ABORT(err); - } - term->array = $2; - $$ = term; -} -| -name_or_raw array '=' PE_VALUE -{ - struct parse_events_term *term; - int err = parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, $1, $4, false, &@1, &@4); - - if (err) { - free($1); - free($2.ranges); - PE_ABORT(err); - } - term->array = $2; - $$ = term; -} -| -PE_DRV_CFG_TERM -{ - struct parse_events_term *term; - char *config = strdup($1); - int err; - - if (!config) - YYNOMEM; - err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_DRV_CFG, config, $1, &@1, NULL); - if (err) { - free($1); - free(config); - PE_ABORT(err); - } - $$ = term; -} - -array: -'[' array_terms ']' -{ - $$ = $2; -} -| -PE_ARRAY_ALL -{ - $$.nr_ranges = 0; - $$.ranges = NULL; -} - -array_terms: -array_terms ',' array_term -{ - struct parse_events_array new_array; - - new_array.nr_ranges = $1.nr_ranges + $3.nr_ranges; - new_array.ranges = realloc($1.ranges, - sizeof(new_array.ranges[0]) * - new_array.nr_ranges); - if (!new_array.ranges) - YYNOMEM; - memcpy(&new_array.ranges[$1.nr_ranges], $3.ranges, - $3.nr_ranges * sizeof(new_array.ranges[0])); - free($3.ranges); - $$ = new_array; -} -| -array_term - -array_term: -PE_VALUE -{ - struct parse_events_array array; - - array.nr_ranges = 1; - array.ranges = malloc(sizeof(array.ranges[0])); - if (!array.ranges) - YYNOMEM; - array.ranges[0].start = $1; - array.ranges[0].length = 1; - $$ = array; -} -| -PE_VALUE PE_ARRAY_RANGE PE_VALUE -{ - struct parse_events_array array; - - if ($3 < $1) { - struct parse_events_state *parse_state = _parse_state; - struct parse_events_error *error = parse_state->error; - char *err_str; - - if (asprintf(&err_str, "Expected '%ld' to be less-than '%ld'", $3, $1) < 0) - err_str = NULL; - - parse_events_error__handle(error, @1.first_column, err_str, NULL); - YYABORT; - } - array.nr_ranges = 1; - array.ranges = malloc(sizeof(array.ranges[0])); - if (!array.ranges) - YYNOMEM; - array.ranges[0].start = $1; - array.ranges[0].length = $3 - $1 + 1; - $$ = array; -} sep_dc: ':' | -- GitLab From c9b57eb8dcb097e32f9a73f88f6d13c57ce65b4d Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 27 Jul 2023 17:12:12 -0700 Subject: [PATCH 0755/3445] perf parse-events: Remove array remnants parse_events_array was set up by event term parsing, which no longer exists. Remove this struct and references to it. Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Eduard Zingerman Cc: He Kuang Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Rob Herring Cc: Wang Nan Cc: Wang ShaoBo Cc: YueHaibing Cc: bpf@vger.kernel.org Link: https://lore.kernel.org/r/20230728001212.457900-4-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/bpf-loader.c | 101 --------------------------------- tools/perf/util/parse-events.c | 8 --- tools/perf/util/parse-events.h | 10 ---- 3 files changed, 119 deletions(-) diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 8f4c76f2265a4..50e42698cbb72 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -1088,16 +1088,12 @@ enum bpf_map_op_type { enum bpf_map_key_type { BPF_MAP_KEY_ALL, - BPF_MAP_KEY_RANGES, }; struct bpf_map_op { struct list_head list; enum bpf_map_op_type op_type; enum bpf_map_key_type key_type; - union { - struct parse_events_array array; - } k; union { u64 value; struct evsel *evsel; @@ -1113,8 +1109,6 @@ bpf_map_op__delete(struct bpf_map_op *op) { if (!list_empty(&op->list)) list_del_init(&op->list); - if (op->key_type == BPF_MAP_KEY_RANGES) - parse_events__clear_array(&op->k.array); free(op); } @@ -1193,18 +1187,6 @@ bpf_map_op_setkey(struct bpf_map_op *op, struct parse_events_term *term) if (!term) return 0; - if (term->array.nr_ranges) { - size_t memsz = term->array.nr_ranges * - sizeof(op->k.array.ranges[0]); - - op->k.array.ranges = memdup(term->array.ranges, memsz); - if (!op->k.array.ranges) { - pr_debug("Not enough memory to alloc indices for map\n"); - return -ENOMEM; - } - op->key_type = BPF_MAP_KEY_RANGES; - op->k.array.nr_ranges = term->array.nr_ranges; - } return 0; } @@ -1241,18 +1223,6 @@ bpf_map_op__clone(struct bpf_map_op *op) } INIT_LIST_HEAD(&newop->list); - if (op->key_type == BPF_MAP_KEY_RANGES) { - size_t memsz = op->k.array.nr_ranges * - sizeof(op->k.array.ranges[0]); - - newop->k.array.ranges = memdup(op->k.array.ranges, memsz); - if (!newop->k.array.ranges) { - pr_debug("Failed to alloc indices for map\n"); - free(newop); - return NULL; - } - } - return newop; } @@ -1453,40 +1423,6 @@ struct bpf_obj_config__map_func bpf_obj_config__map_funcs[] = { {"event", bpf_map__config_event}, }; -static int -config_map_indices_range_check(struct parse_events_term *term, - struct bpf_map *map, - const char *map_name) -{ - struct parse_events_array *array = &term->array; - unsigned int i; - - if (!array->nr_ranges) - return 0; - if (!array->ranges) { - pr_debug("ERROR: map %s: array->nr_ranges is %d but range array is NULL\n", - map_name, (int)array->nr_ranges); - return -BPF_LOADER_ERRNO__INTERNAL; - } - - if (!map) { - pr_debug("Map '%s' is invalid\n", map_name); - return -BPF_LOADER_ERRNO__INTERNAL; - } - - for (i = 0; i < array->nr_ranges; i++) { - unsigned int start = array->ranges[i].start; - size_t length = array->ranges[i].length; - unsigned int idx = start + length - 1; - - if (idx >= bpf_map__max_entries(map)) { - pr_debug("ERROR: index %d too large\n", idx); - return -BPF_LOADER_ERRNO__OBJCONF_MAP_IDX2BIG; - } - } - return 0; -} - static int bpf__obj_config_map(struct bpf_object *obj, struct parse_events_term *term, @@ -1522,12 +1458,6 @@ bpf__obj_config_map(struct bpf_object *obj, goto out; } - *key_scan_pos += strlen(map_opt); - err = config_map_indices_range_check(term, map, map_name); - if (err) - goto out; - *key_scan_pos -= strlen(map_opt); - for (i = 0; i < ARRAY_SIZE(bpf_obj_config__map_funcs); i++) { struct bpf_obj_config__map_func *func = &bpf_obj_config__map_funcs[i]; @@ -1576,7 +1506,6 @@ typedef int (*map_config_func_t)(const char *name, int map_fd, const struct bpf_map *map, struct bpf_map_op *op, void *pkey, void *arg); - static int foreach_key_array_all(map_config_func_t func, void *arg, const char *name, @@ -1597,32 +1526,6 @@ foreach_key_array_all(map_config_func_t func, return 0; } -static int -foreach_key_array_ranges(map_config_func_t func, void *arg, - const char *name, int map_fd, - const struct bpf_map *map, - struct bpf_map_op *op) -{ - unsigned int i, j; - int err; - - for (i = 0; i < op->k.array.nr_ranges; i++) { - unsigned int start = op->k.array.ranges[i].start; - size_t length = op->k.array.ranges[i].length; - - for (j = 0; j < length; j++) { - unsigned int idx = start + j; - - err = func(name, map_fd, map, op, &idx, arg); - if (err) { - pr_debug("ERROR: failed to insert value to %s[%u]\n", - name, idx); - return err; - } - } - } - return 0; -} static int bpf_map_config_foreach_key(struct bpf_map *map, @@ -1663,10 +1566,6 @@ bpf_map_config_foreach_key(struct bpf_map *map, err = foreach_key_array_all(func, arg, name, map_fd, map, op); break; - case BPF_MAP_KEY_RANGES: - err = foreach_key_array_ranges(func, arg, name, - map_fd, map, op); - break; default: pr_debug("ERROR: keytype for map '%s' invalid\n", name); diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 37614dc1d6982..52e9f062b26bc 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -2716,9 +2716,6 @@ int parse_events_term__clone(struct parse_events_term **new, void parse_events_term__delete(struct parse_events_term *term) { - if (term->array.nr_ranges) - zfree(&term->array.ranges); - if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM) zfree(&term->val.str); @@ -2769,11 +2766,6 @@ void parse_events_terms__delete(struct list_head *terms) free(terms); } -void parse_events__clear_array(struct parse_events_array *a) -{ - zfree(&a->ranges); -} - void parse_events_evlist_error(struct parse_events_state *parse_state, int idx, const char *str) { diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index e59b338058860..b77ff619a6236 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -81,17 +81,8 @@ enum { __PARSE_EVENTS__TERM_TYPE_NR, }; -struct parse_events_array { - size_t nr_ranges; - struct { - unsigned int start; - size_t length; - } *ranges; -}; - struct parse_events_term { char *config; - struct parse_events_array array; union { char *str; u64 num; @@ -162,7 +153,6 @@ int parse_events_term__clone(struct parse_events_term **new, void parse_events_term__delete(struct parse_events_term *term); void parse_events_terms__delete(struct list_head *terms); void parse_events_terms__purge(struct list_head *terms); -void parse_events__clear_array(struct parse_events_array *a); int parse_events__modifier_event(struct list_head *list, char *str, bool add); int parse_events__modifier_group(struct list_head *list, char *event_mod); int parse_events_name(struct list_head *list, const char *name); -- GitLab From 11cb1ed477692320af116c543b47084cbb898026 Mon Sep 17 00:00:00 2001 From: Aditya Gupta Date: Tue, 25 Jul 2023 11:46:49 +0530 Subject: [PATCH 0756/3445] perf tests task_analyzer: Check perf build options for libtraceevent support Currently we depend on output of 'perf record -e "sched:sched_switch"', to check whether perf was built with libtraceevent support. Instead, a more straightforward approach can be to check the build options, using 'perf version --build-options', to check for libtraceevent support. When perf is compiled WITHOUT libtraceevent ('make NO_LIBTRACEEVENT=1'), 'perf version --build-options' outputs (output trimmed): ... libtraceevent: [ OFF ] # HAVE_LIBTRACEEVENT ... While, when perf is compiled WITH libtraceevent, 'perf version --build-options' outputs: ... libtraceevent: [ on ] # HAVE_LIBTRACEEVENT ... Committer notes: Removed one grep in the pipleline by combining the two into just one expression that covers the OFF + HAVE_LIBTRACEEVENT. Suggested-by: Ian Rogers Signed-off-by: Aditya Gupta Cc: Athira Rajeev Cc: Disha Goel Cc: Jiri Olsa Cc: Kajol Jain Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230725061649.34937-1-adityag@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/test_task_analyzer.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/tests/shell/test_task_analyzer.sh b/tools/perf/tests/shell/test_task_analyzer.sh index 0095abbe20cab..92d15154ba795 100755 --- a/tools/perf/tests/shell/test_task_analyzer.sh +++ b/tools/perf/tests/shell/test_task_analyzer.sh @@ -52,7 +52,7 @@ find_str_or_fail() { # check if perf is compiled with libtraceevent support skip_no_probe_record_support() { - perf record -e "sched:sched_switch" -a -- sleep 1 2>&1 | grep "libtraceevent is necessary for tracepoint support" && return 2 + perf version --build-options | grep -q " OFF .* HAVE_LIBTRACEEVENT" && return 2 return 0 } -- GitLab From 38beba673b43b168906fff54f59cf004d2eb8120 Mon Sep 17 00:00:00 2001 From: Akanksha J N Date: Sun, 9 Jul 2023 23:57:35 +0530 Subject: [PATCH 0757/3445] perf tests trace+probe_vfs_getname: Fix shellcheck warnings about word splitting/quoting Running shellcheck -S on probe_vfs_getname.sh, throws below warnings: Before fix: $ shellcheck -S warning trace+probe_vfs_getname.sh In trace+probe_vfs_getname.sh line 13: . $(dirname $0)/lib/probe.sh ^-----------^ SC2046 (warning): Quote this to prevent word splitting. In trace+probe_vfs_getname.sh line 18: . $(dirname $0)/lib/probe_vfs_getname.sh ^-----------^ SC2046 (warning): Quote this to prevent word splitting. In trace+probe_vfs_getname.sh line 21: evts=$(echo $(perf list syscalls:sys_enter_open* 2>/dev/null | grep -E 'open(at)? ' | sed -r 's/.*sys_enter_([a-z]+) +\[.*$/\1/') | sed 's/ /,/') ^-- SC2046 (warning): Quote this to prevent word splitting. Fix the shellcheck warnings by adding quotes to prevent word splitting. Signed-off-by: Akanksha J N Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-2-atrajeev@linux.vnet.ibm.com Signed-off-by: Athira Rajeev Signed-off-by: Kajol Jain Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/trace+probe_vfs_getname.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/tests/shell/trace+probe_vfs_getname.sh b/tools/perf/tests/shell/trace+probe_vfs_getname.sh index 0a4bac3dd77eb..db2ff141f7037 100755 --- a/tools/perf/tests/shell/trace+probe_vfs_getname.sh +++ b/tools/perf/tests/shell/trace+probe_vfs_getname.sh @@ -10,15 +10,15 @@ # SPDX-License-Identifier: GPL-2.0 # Arnaldo Carvalho de Melo , 2017 -. $(dirname $0)/lib/probe.sh +. "$(dirname $0)"/lib/probe.sh skip_if_no_perf_probe || exit 2 skip_if_no_perf_trace || exit 2 -. $(dirname $0)/lib/probe_vfs_getname.sh +. "$(dirname $0)"/lib/probe_vfs_getname.sh trace_open_vfs_getname() { - evts=$(echo $(perf list syscalls:sys_enter_open* 2>/dev/null | grep -E 'open(at)? ' | sed -r 's/.*sys_enter_([a-z]+) +\[.*$/\1/') | sed 's/ /,/') + evts="$(echo "$(perf list syscalls:sys_enter_open* 2>/dev/null | grep -E 'open(at)? ' | sed -r 's/.*sys_enter_([a-z]+) +\[.*$/\1/')" | sed ':a;N;s:\n:,:g')" perf trace -e $evts touch $file 2>&1 | \ grep -E " +[0-9]+\.[0-9]+ +\( +[0-9]+\.[0-9]+ ms\): +touch\/[0-9]+ open(at)?\((dfd: +CWD, +)?filename: +${file}, +flags: CREAT\|NOCTTY\|NONBLOCK\|WRONLY, +mode: +IRUGO\|IWUGO\) += +[0-9]+$" } -- GitLab From 7b485d9468903dea570542dc814f778d268162f6 Mon Sep 17 00:00:00 2001 From: Kajol Jain Date: Sun, 9 Jul 2023 23:57:36 +0530 Subject: [PATCH 0758/3445] perf tests probe_vfs_getname: Fix shellcheck warnings about word splitting/quoting Running shellcheck on probe_vfs_getname.sh throws below warning: In tests/shell/probe_vfs_getname.sh line 7: . $(dirname $0)/lib/probe.sh ^-----------^ SC2046 (warning): Quote this to prevent word splitting. In tests/shell/probe_vfs_getname.sh line 11: . $(dirname $0)/lib/probe_vfs_getname.sh ^-----------^ SC2046 (warning): Quote this to prevent word splitting. Fixed the warning by adding quotes to avoid word splitting. ShellCheck result with patch: # shellcheck -S warning probe_vfs_getname.sh # Signed-off-by: Kajol Jain Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-3-atrajeev@linux.vnet.ibm.com Signed-off-by: Athira Rajeev Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/probe_vfs_getname.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/tests/shell/probe_vfs_getname.sh b/tools/perf/tests/shell/probe_vfs_getname.sh index 5d1b63d3f3e1f..871243d6d03a2 100755 --- a/tools/perf/tests/shell/probe_vfs_getname.sh +++ b/tools/perf/tests/shell/probe_vfs_getname.sh @@ -4,11 +4,11 @@ # SPDX-License-Identifier: GPL-2.0 # Arnaldo Carvalho de Melo , 2017 -. $(dirname $0)/lib/probe.sh +. "$(dirname $0)"/lib/probe.sh skip_if_no_perf_probe || exit 2 -. $(dirname $0)/lib/probe_vfs_getname.sh +. "$(dirname $0)"/lib/probe_vfs_getname.sh add_probe_vfs_getname || skip_if_no_debuginfo err=$? -- GitLab From a225c3049791b1591debf07fa9f4377b2c331ecc Mon Sep 17 00:00:00 2001 From: Kajol Jain Date: Sun, 9 Jul 2023 23:57:37 +0530 Subject: [PATCH 0759/3445] perf tests record_offcpu: Fix shellcheck warnings about word splitting/quoting and signal names case Running shellcheck on record_offcpu.sh throws below warning: In tests/shell/record_offcpu.sh line 13: trap - exit term int ^--^ SC3049 (warning): In POSIX sh, using lower/mixed case for signal names is undefined. ^--^ SC3049 (warning): In POSIX sh, using lower/mixed case for signal names is undefined. ^-^ SC3049 (warning): In POSIX sh, using lower/mixed case for signal names is undefined. In tests/shell/record_offcpu.sh line 20: trap trap_cleanup exit term int ^--^ SC3049 (warning): In POSIX sh, using lower/mixed case for signal names is undefined. ^--^ SC3049 (warning): In POSIX sh, using lower/mixed case for signal names is undefined. ^-^ SC3049 (warning): In POSIX sh, using lower/mixed case for signal names is undefined. In tests/shell/record_offcpu.sh line 25: if [ `id -u` != 0 ] ^-----^ SC2046 (warning): Quote this to prevent word splitting. Fixed the warnings by: - Capitalize signals(INT, TERM, EXIT) to avoid mixed/lower case naming of signals. - Adding quotes to avoid word splitting. Result from shellcheck after patch changes: $ shellcheck -S warning record_offcpu.sh $ Signed-off-by: Kajol Jain Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-4-atrajeev@linux.vnet.ibm.com Signed-off-by: Athira Rajeev Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/record_offcpu.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/tests/shell/record_offcpu.sh b/tools/perf/tests/shell/record_offcpu.sh index f062ae9a95e1a..a0d14cd0aa798 100755 --- a/tools/perf/tests/shell/record_offcpu.sh +++ b/tools/perf/tests/shell/record_offcpu.sh @@ -10,19 +10,19 @@ perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) cleanup() { rm -f ${perfdata} rm -f ${perfdata}.old - trap - exit term int + trap - EXIT TERM INT } trap_cleanup() { cleanup exit 1 } -trap trap_cleanup exit term int +trap trap_cleanup EXIT TERM INT test_offcpu_priv() { echo "Checking off-cpu privilege" - if [ `id -u` != 0 ] + if [ "$(id -u)" != 0 ] then echo "off-cpu test [Skipped permission]" err=2 -- GitLab From edf197cb9da529ef854ba21311ddbaddc7098eba Mon Sep 17 00:00:00 2001 From: Kajol Jain Date: Sun, 9 Jul 2023 23:57:38 +0530 Subject: [PATCH 0760/3445] perf tests lock_contention: Fix shellcheck issue about quoting to avoid word splitting Running shellcheck on lock_contention.sh generates below warning: In tests/shell/lock_contention.sh line 24: if [ `id -u` != 0 ]; then ^-----^ SC2046 (warning): Quote this to prevent word splitting. In tests/shell/lock_contention.sh line 160: local type=$(head -1 "${result}" | awk '{ print $8 }' | sed -e 's/:.*//') ^--------^ SC3043 (warning): In POSIX sh, 'local' is undefined. ^--^ SC2155 (warning): Declare and assign separately to avoid masking return values. ^-- SC2046 (warning): Quote this to prevent word splitting. Fixed above warnings by: - Adding quotes to avoid word splitting. - Fixing shellcheck warnings for local usage, by prefixing function name to the variable. Signed-off-by: Kajol Jain Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-5-atrajeev@linux.vnet.ibm.com Signed-off-by: Athira Rajeev Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/lock_contention.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/perf/tests/shell/lock_contention.sh b/tools/perf/tests/shell/lock_contention.sh index 4a194420416e0..d120e83db7d91 100755 --- a/tools/perf/tests/shell/lock_contention.sh +++ b/tools/perf/tests/shell/lock_contention.sh @@ -21,7 +21,7 @@ trap_cleanup() { trap trap_cleanup EXIT TERM INT check() { - if [ `id -u` != 0 ]; then + if [ "$(id -u)" != 0 ]; then echo "[Skip] No root permission" err=2 exit @@ -157,10 +157,10 @@ test_lock_filter() perf lock contention -i ${perfdata} -L tasklist_lock -q 2> ${result} # find out the type of tasklist_lock - local type=$(head -1 "${result}" | awk '{ print $8 }' | sed -e 's/:.*//') + test_lock_filter_type=$(head -1 "${result}" | awk '{ print $8 }' | sed -e 's/:.*//') - if [ "$(grep -c -v "${type}" "${result}")" != "0" ]; then - echo "[Fail] Recorded result should not have non-${type} locks:" "$(cat "${result}")" + if [ "$(grep -c -v "${test_lock_filter_type}" "${result}")" != "0" ]; then + echo "[Fail] Recorded result should not have non-${test_lock_filter_type} locks:" "$(cat "${result}")" err=1 exit fi @@ -170,8 +170,8 @@ test_lock_filter() fi perf lock con -a -b -L tasklist_lock -q -- perf bench sched messaging > /dev/null 2> ${result} - if [ "$(grep -c -v "${type}" "${result}")" != "0" ]; then - echo "[Fail] BPF result should not have non-${type} locks:" "$(cat "${result}")" + if [ "$(grep -c -v "${test_lock_filter_type}" "${result}")" != "0" ]; then + echo "[Fail] BPF result should not have non-${test_lock_filter_type} locks:" "$(cat "${result}")" err=1 exit fi -- GitLab From 0dd1f815545d7210150642741c364521cc5cf116 Mon Sep 17 00:00:00 2001 From: Kajol Jain Date: Sun, 9 Jul 2023 23:57:39 +0530 Subject: [PATCH 0761/3445] perf test stat_bpf_counters_cgrp: Fix shellcheck issue about logical operators Running shellcheck on lock_contention.sh generates below warning: In stat_bpf_counters_cgrp.sh line 28: if [ -d /sys/fs/cgroup/system.slice -a -d /sys/fs/cgroup/user.slice ]; then ^-- SC2166 (warning): Prefer [ p ] && [ q ] as [ p -a q ] is not well defined. In stat_bpf_counters_cgrp.sh line 34: local self_cgrp=$(grep perf_event /proc/self/cgroup | cut -d: -f3) ^-------------^ SC3043 (warning): In POSIX sh, 'local' is undefined. ^-------^ SC2155 (warning): Declare and assign separately to avoid masking return values. ^-- SC2046 (warning): Quote this to prevent word splitting. In stat_bpf_counters_cgrp.sh line 51: local output ^----------^ SC3043 (warning): In POSIX sh, 'local' is undefined. In stat_bpf_counters_cgrp.sh line 65: local output ^----------^ SC3043 (warning): In POSIX sh, 'local' is undefined. Fixed above warnings by: - Changing the expression [p -a q] to [p] && [q]. - Fixing shellcheck warnings for local usage, by prefixing function name to the variable. Signed-off-by: Kajol Jain Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-6-atrajeev@linux.vnet.ibm.com Signed-off-by: Athira Rajeev Signed-off-by: Arnaldo Carvalho de Melo --- .../tests/shell/stat_bpf_counters_cgrp.sh | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh b/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh index d724855d097c2..a74440a00b6b6 100755 --- a/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh +++ b/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh @@ -25,22 +25,22 @@ check_bpf_counter() find_cgroups() { # try usual systemd slices first - if [ -d /sys/fs/cgroup/system.slice -a -d /sys/fs/cgroup/user.slice ]; then + if [ -d /sys/fs/cgroup/system.slice ] && [ -d /sys/fs/cgroup/user.slice ]; then test_cgroups="system.slice,user.slice" return fi # try root and self cgroups - local self_cgrp=$(grep perf_event /proc/self/cgroup | cut -d: -f3) - if [ -z ${self_cgrp} ]; then + find_cgroups_self_cgrp=$(grep perf_event /proc/self/cgroup | cut -d: -f3) + if [ -z ${find_cgroups_self_cgrp} ]; then # cgroup v2 doesn't specify perf_event - self_cgrp=$(grep ^0: /proc/self/cgroup | cut -d: -f3) + find_cgroups_self_cgrp=$(grep ^0: /proc/self/cgroup | cut -d: -f3) fi - if [ -z ${self_cgrp} ]; then + if [ -z ${find_cgroups_self_cgrp} ]; then test_cgroups="/" else - test_cgroups="/,${self_cgrp}" + test_cgroups="/,${find_cgroups_self_cgrp}" fi } @@ -48,13 +48,11 @@ find_cgroups() # Just check if it runs without failure and has non-zero results. check_system_wide_counted() { - local output - - output=$(perf stat -a --bpf-counters --for-each-cgroup ${test_cgroups} -e cpu-clock -x, sleep 1 2>&1) - if echo ${output} | grep -q -F "&1) + if echo ${check_system_wide_counted_output} | grep -q -F "&1) - if echo ${output} | grep -q -F "&1) + if echo ${check_cpu_list_counted_output} | grep -q -F " Date: Sun, 9 Jul 2023 23:57:40 +0530 Subject: [PATCH 0762/3445] perf tests: Address signal case issues detected via shellcheck Running shellcheck -S on test_arm_spe_fork.sh throws below warnings: In tests/shell/test_arm_spe_fork.sh line 25: trap cleanup_files exit term int ^--^ SC3049 (warning): In POSIX sh, using lower/mixed case for signal names is undefined. ^--^ SC3049 (warning): In POSIX sh, using lower/mixed case for signal names is undefined. ^-^ SC3049 (warning): In POSIX sh, using lower/mixed case for signal names is undefined. Fixed this issue by using uppercase for "EXIT", "TERM" and "INIT" signals to avoid using lower/mixed case for signal names as input. Signed-off-by: Athira Rajeev Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Kajol Jain Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-7-atrajeev@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/test_arm_spe_fork.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/tests/shell/test_arm_spe_fork.sh b/tools/perf/tests/shell/test_arm_spe_fork.sh index fad361675a1d1..1a7e6a82d0e34 100755 --- a/tools/perf/tests/shell/test_arm_spe_fork.sh +++ b/tools/perf/tests/shell/test_arm_spe_fork.sh @@ -22,7 +22,7 @@ cleanup_files() rm -f ${PERF_DATA} } -trap cleanup_files exit term int +trap cleanup_files EXIT TERM INT echo "Recording workload..." perf record -o ${PERF_DATA} -e arm_spe/period=65536/ -vvv -- $TEST_PROGRAM > ${PERF_RECORD_LOG} 2>&1 & -- GitLab From faae152aa6d237001e55bfcb9026cadf9531fc3c Mon Sep 17 00:00:00 2001 From: Athira Rajeev Date: Sun, 9 Jul 2023 23:57:41 +0530 Subject: [PATCH 0763/3445] perf tests stat+csv_summary: Fix unused variable references detected via shellcheck Running shellcheck on stat+csv_summary.sh throws below warnings: In tests/shell/stat+csv_summary.sh line 26: while read num event run pct ^-^ SC2034 (warning): num appears unused. Verify use (or export if used externally). ^---^ SC2034 (warning): event appears unused. Verify use (or export if used externally). ^-^ SC2034 (warning): run appears unused. Verify use (or export if used externally). ^-^ SC2034 (warning): pct appears unused. Verify use (or export if used externally). These variables are intentionally unused since they are needed to parse through the output. Use "_" as a prefix for these throw away variables. Signed-off-by: Athira Rajeev Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Kajol Jain Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-8-atrajeev@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/stat+csv_summary.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/tests/shell/stat+csv_summary.sh b/tools/perf/tests/shell/stat+csv_summary.sh index 5571ff75eb428..8bae9c8a835e1 100755 --- a/tools/perf/tests/shell/stat+csv_summary.sh +++ b/tools/perf/tests/shell/stat+csv_summary.sh @@ -10,7 +10,7 @@ set -e # perf stat -e cycles -x' ' -I1000 --interval-count 1 --summary 2>&1 | \ grep -e summary | \ -while read summary num event run pct +while read summary _num _event _run _pct do if [ $summary != "summary" ]; then exit 1 @@ -23,7 +23,7 @@ done # perf stat -e cycles -x' ' -I1000 --interval-count 1 --summary --no-csv-summary 2>&1 | \ grep -e summary | \ -while read num event run pct +while read _num _event _run _pct do exit 1 done -- GitLab From 38b3fa07f19e0c6b22ea1167d82b184bb0e0a830 Mon Sep 17 00:00:00 2001 From: Athira Rajeev Date: Sun, 9 Jul 2023 23:57:42 +0530 Subject: [PATCH 0764/3445] perf tests perf_dat _converter_json: Use quoting to avoid word splitting Running shellcheck on test_perf_data_converter_json.sh throws below warning: In tests/shell/test_perf_data_converter_json.sh line 42: if [ $(cat "${result}" | wc -l) -gt "0" ] ; then ^------------------------^ SC2046 (warning): Quote this to prevent word splitting. Fixed the warning by adding quotes to avoid word splitting. ShellCheck result with patch: # shellcheck -S warning test_perf_data_converter_json.sh # Signed-off-by: Athira Rajeev Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Kajol Jain Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-9-atrajeev@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/test_perf_data_converter_json.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/tests/shell/test_perf_data_converter_json.sh b/tools/perf/tests/shell/test_perf_data_converter_json.sh index 72ac6c83231c0..6ded58f98f55b 100755 --- a/tools/perf/tests/shell/test_perf_data_converter_json.sh +++ b/tools/perf/tests/shell/test_perf_data_converter_json.sh @@ -39,7 +39,7 @@ test_json_converter_command() echo "Testing Perf Data Convertion Command to JSON" perf record -o "$perfdata" -F 99 -g -- perf test -w noploop > /dev/null 2>&1 perf data convert --to-json "$result" --force -i "$perfdata" >/dev/null 2>&1 - if [ $(cat "${result}" | wc -l) -gt "0" ] ; then + if [ "$(cat ${result} | wc -l)" -gt "0" ] ; then echo "Perf Data Converter Command to JSON [SUCCESS]" else echo "Perf Data Converter Command to JSON [FAILED]" -- GitLab From d10eedd87bb3e7678c3a0f77a5cfe7150a318ee2 Mon Sep 17 00:00:00 2001 From: Athira Rajeev Date: Sun, 9 Jul 2023 23:57:43 +0530 Subject: [PATCH 0765/3445] perf tests stat_bpf_counters: Fix usage of '==' to address shellcheck warning Running shellcheck on stat_bpf_counter.sh generates below warning: In tests/shell/stat_bpf_counters.sh line 34: if [ "$base_cycles" == "&1 | awk '/cycles/ {print $1}') -if [ "$bpf_cycles" == " Date: Sun, 9 Jul 2023 23:57:44 +0530 Subject: [PATCH 0766/3445] perf tests stat+shadow_stat: Fix shellcheck warning about unused variable Running shellcheck on stat+shadow_stat.sh generates below warning: In tests/shell/stat+shadow_stat.sh line 48: while read cpu num evt hash ipc rest ^--^ SC2034 (warning): hash appears unused. Verify use (or export if used externally). This variable is intentionally unused since it is needed to parse through the output. Use "_" as a prefix for this throw away variable. Signed-off-by: Athira Rajeev Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Kajol Jain Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-11-atrajeev@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/stat+shadow_stat.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/tests/shell/stat+shadow_stat.sh b/tools/perf/tests/shell/stat+shadow_stat.sh index 0e9cba84e757f..a1918a15e36a1 100755 --- a/tools/perf/tests/shell/stat+shadow_stat.sh +++ b/tools/perf/tests/shell/stat+shadow_stat.sh @@ -14,7 +14,7 @@ test_global_aggr() { perf stat -a --no-big-num -e cycles,instructions sleep 1 2>&1 | \ grep -e cycles -e instructions | \ - while read num evt hash ipc rest + while read num evt _hash ipc rest do # skip not counted events if [ "$num" = "&1 | \ grep ^CPU | \ - while read cpu num evt hash ipc rest + while read cpu num evt _hash ipc rest do # skip not counted events if [ "$num" = " Date: Sun, 9 Jul 2023 23:57:45 +0530 Subject: [PATCH 0767/3445] perf tests asm_pure_loop: Fix shellcheck warning about word splitting/quote Running shellcheck on asm_pure_loop.sh throws below warning: In coresight/asm_pure_loop.sh line 8: . $(dirname $0)/../lib/coresight.sh ^-----------^ SC2046 (warning): Quote this to prevent word splitting. Fixed the warning by adding quotes to avoid word splitting. ShellCheck result with patch: # shellcheck -S warning coresight/asm_pure_loop.sh # Signed-off-by: Kajol Jain Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-12-atrajeev@linux.vnet.ibm.com Signed-off-by: Athira Rajeev Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/coresight/asm_pure_loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/tests/shell/coresight/asm_pure_loop.sh b/tools/perf/tests/shell/coresight/asm_pure_loop.sh index 569e9d46162bc..779bc8608e1eb 100755 --- a/tools/perf/tests/shell/coresight/asm_pure_loop.sh +++ b/tools/perf/tests/shell/coresight/asm_pure_loop.sh @@ -5,7 +5,7 @@ # Carsten Haitzler , 2021 TEST="asm_pure_loop" -. $(dirname $0)/../lib/coresight.sh +. "$(dirname $0)"/../lib/coresight.sh ARGS="" DATV="out" DATA="$DATD/perf-$TEST-$DATV.data" -- GitLab From 5f83f1d58821660ced1c7330a6dd3ff013240f66 Mon Sep 17 00:00:00 2001 From: Kajol Jain Date: Sun, 9 Jul 2023 23:57:46 +0530 Subject: [PATCH 0768/3445] perf tests memcpy_thread_16k_10: Fix shellcheck warning about word splitting/quote Running shellcheck on memcpy_thread_16k_10.sh throws below warning: In memcpy_thread_16k_10.sh line 8: . $(dirname $0)/../lib/coresight.sh ^-----------^ SC2046 (warning): Quote this to prevent word splitting. Fixed the warning by adding quotes to avoid word splitting. ShellCheck result with patch: # shellcheck -S warning coresight/memcpy_thread_16k_10.sh # Signed-off-by: Kajol Jain Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-13-atrajeev@linux.vnet.ibm.com Signed-off-by: Athira Rajeev Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/coresight/memcpy_thread_16k_10.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/tests/shell/coresight/memcpy_thread_16k_10.sh b/tools/perf/tests/shell/coresight/memcpy_thread_16k_10.sh index d21ba8545938d..08a44e52ce9b0 100755 --- a/tools/perf/tests/shell/coresight/memcpy_thread_16k_10.sh +++ b/tools/perf/tests/shell/coresight/memcpy_thread_16k_10.sh @@ -5,7 +5,7 @@ # Carsten Haitzler , 2021 TEST="memcpy_thread" -. $(dirname $0)/../lib/coresight.sh +. "$(dirname $0)"/../lib/coresight.sh ARGS="16 10 1" DATV="16k_10" DATA="$DATD/perf-$TEST-$DATV.data" -- GitLab From 05ef238cd05db7b3b2e596027c403964de1d3919 Mon Sep 17 00:00:00 2001 From: Kajol Jain Date: Sun, 9 Jul 2023 23:57:47 +0530 Subject: [PATCH 0769/3445] perf tests lib probe: Fix shellcheck warning about about missing shebang Running shellcheck on probe.sh throws below warning: In lib/probe.sh line 1: ^-- SC2148 (error): Tips depend on target shell and yours is unknown. Add a shebang or a 'shell' directive. Fixed the warnings by adding shell directive. Signed-off-by: Kajol Jain Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-14-atrajeev@linux.vnet.ibm.com Signed-off-by: Athira Rajeev Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/lib/probe.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/tests/shell/lib/probe.sh b/tools/perf/tests/shell/lib/probe.sh index 51e3f60baba0c..5aa6e2ec57344 100644 --- a/tools/perf/tests/shell/lib/probe.sh +++ b/tools/perf/tests/shell/lib/probe.sh @@ -1,3 +1,4 @@ +#!/bin/bash # SPDX-License-Identifier: GPL-2.0 # Arnaldo Carvalho de Melo , 2017 -- GitLab From f188b2ce65730178f8dc0d105beb759719a12e6c Mon Sep 17 00:00:00 2001 From: Kajol Jain Date: Sun, 9 Jul 2023 23:57:48 +0530 Subject: [PATCH 0770/3445] perf beauty arch_errno_names: Fix shellcheck issue about local variables Running shellcheck on arch_errno_names.sh generates below warning: In arch_errno_names.sh line 20: local arch="$1" ^--------^ SC3043 (warning): In POSIX sh, 'local' is undefined. ...... In arch_errno_names.sh line 61: local arch ^--------^ SC3043 (warning): In POSIX sh, 'local' is undefined. In arch_errno_names.sh line 67: printf '\t\treturn errno_to_name__%s(err);\n' $(arch_string "$arch") ^--------------------^ SC2046 (warning): Quote this to prevent word splitting. In arch_errno_names.sh line 69: printf '\treturn errno_to_name__%s(err);\n' $(arch_string "$default") ^-----------------------^ SC2046 (warning): Quote this to prevent word splitting. Fixed the warnings by: - Fixing shellcheck warnings for local usage, by removing local from the variable names - Adding quotes to avoid word splitting Signed-off-by: Kajol Jain Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-15-atrajeev@linux.vnet.ibm.com Signed-off-by: Athira Rajeev Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/trace/beauty/arch_errno_names.sh | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/tools/perf/trace/beauty/arch_errno_names.sh b/tools/perf/trace/beauty/arch_errno_names.sh index 37c53bac5f56e..cc09dcaa891e0 100755 --- a/tools/perf/trace/beauty/arch_errno_names.sh +++ b/tools/perf/trace/beauty/arch_errno_names.sh @@ -17,8 +17,7 @@ arch_string() asm_errno_file() { - local arch="$1" - local header + arch="$1" header="$toolsdir/arch/$arch/include/uapi/asm/errno.h" if test -r "$header"; then @@ -30,8 +29,7 @@ asm_errno_file() create_errno_lookup_func() { - local arch=$(arch_string "$1") - local nr name + arch=$(arch_string "$1") printf "static const char *errno_to_name__%s(int err)\n{\n\tswitch (err) {\n" $arch @@ -44,8 +42,8 @@ create_errno_lookup_func() process_arch() { - local arch="$1" - local asm_errno=$(asm_errno_file "$arch") + arch="$1" + asm_errno=$(asm_errno_file "$arch") $gcc $CFLAGS $include_path -E -dM -x c $asm_errno \ |grep -hE '^#define[[:blank:]]+(E[^[:blank:]]+)[[:blank:]]+([[:digit:]]+).*' \ @@ -56,9 +54,8 @@ process_arch() create_arch_errno_table_func() { - local archlist="$1" - local default="$2" - local arch + archlist="$1" + default="$2" printf 'const char *arch_syscalls__strerrno(const char *arch, int err)\n' printf '{\n' -- GitLab From e936584214b93929eb41ec598959469e3a1f6079 Mon Sep 17 00:00:00 2001 From: Kajol Jain Date: Sun, 9 Jul 2023 23:57:49 +0530 Subject: [PATCH 0771/3445] perf build: Fix shellcheck issue about quotes for check-headers.sh Running shellcheck on check-headers.sh generates below warning: In check-headers.sh line 126: check_2 "tools/$file" "$file" $* ^-- SC2048 (warning): Use "$@" (with quotes) to prevent whitespace problems. In check-headers.sh line 134: check_2 "tools/perf/trace/beauty/$file" "$file" $* ^-- SC2048 (warning): Use "$@" (with quotes) to prevent whitespace problems. In check-headers.sh line 186: cd tools/perf ^-----------^ SC2164 (warning): Use 'cd ... || exit' or 'cd ... || return' in case cd fails. Fixed the warnings by: - Using "$@" instead of $* - Adding exit condition with cd command Signed-off-by: Kajol Jain Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-16-atrajeev@linux.vnet.ibm.com Signed-off-by: Athira Rajeev Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/check-headers.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index a0f1d8adce60d..4314c91978509 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -123,7 +123,7 @@ check () { shift - check_2 "tools/$file" "$file" $* + check_2 "tools/$file" "$file" "$@" } beauty_check () { @@ -131,7 +131,7 @@ beauty_check () { shift - check_2 "tools/perf/trace/beauty/$file" "$file" $* + check_2 "tools/perf/trace/beauty/$file" "$file" "$@" } # Check if we have the kernel headers (tools/perf/../../include), else @@ -183,7 +183,7 @@ done check_2 tools/perf/util/hashmap.h tools/lib/bpf/hashmap.h check_2 tools/perf/util/hashmap.c tools/lib/bpf/hashmap.c -cd tools/perf +cd tools/perf || exit if [ ${#FAILURES[@]} -gt 0 ] then -- GitLab From 5fe0531205688fe9bda0ce94628b133b0f94b229 Mon Sep 17 00:00:00 2001 From: Athira Rajeev Date: Sun, 9 Jul 2023 23:57:50 +0530 Subject: [PATCH 0772/3445] perf tests thread_loop_check_tid_10: Fix shellcheck warnings bout word splitting/quoting Fix the shellcheck warnings for thread_loop_check_tid_10.sh In ./tools/perf/tests/shell/coresight/thread_loop_check_tid_10.sh line 8: . $(dirname $0)/../lib/coresight.sh ^-----------^ SC2046 (warning): Quote this to prevent word splitting. Add quotes to prevent word splitting which are caused by unquoted command expansions. Signed-off-by: Athira Rajeev Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Kajol Jain Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-17-atrajeev@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/coresight/thread_loop_check_tid_10.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/tests/shell/coresight/thread_loop_check_tid_10.sh b/tools/perf/tests/shell/coresight/thread_loop_check_tid_10.sh index 7c13636fc7785..c83a200dede4b 100755 --- a/tools/perf/tests/shell/coresight/thread_loop_check_tid_10.sh +++ b/tools/perf/tests/shell/coresight/thread_loop_check_tid_10.sh @@ -5,7 +5,7 @@ # Carsten Haitzler , 2021 TEST="thread_loop" -. $(dirname $0)/../lib/coresight.sh +. "$(dirname $0)"/../lib/coresight.sh ARGS="10 1" DATV="check-tid-10th" DATA="$DATD/perf-$TEST-$DATV.data" -- GitLab From b19de09bbee61aa9ef9fba392a9c8743019b858f Mon Sep 17 00:00:00 2001 From: Athira Rajeev Date: Sun, 9 Jul 2023 23:57:51 +0530 Subject: [PATCH 0773/3445] perf tests unroll_loop_thread_10: Fix shellcheck warnings about word splitting/quoting Fix the shellcheck warnings for unroll_loop_thread_10.sh Add quotes to prevent word splitting which are caused by unquoted command expansions. Signed-off-by: Athira Rajeev Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Kajol Jain Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-18-atrajeev@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/coresight/unroll_loop_thread_10.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/tests/shell/coresight/unroll_loop_thread_10.sh b/tools/perf/tests/shell/coresight/unroll_loop_thread_10.sh index f48c85230b155..7304e3d3a6ff6 100755 --- a/tools/perf/tests/shell/coresight/unroll_loop_thread_10.sh +++ b/tools/perf/tests/shell/coresight/unroll_loop_thread_10.sh @@ -5,7 +5,7 @@ # Carsten Haitzler , 2021 TEST="unroll_loop_thread" -. $(dirname $0)/../lib/coresight.sh +. "$(dirname $0)"/../lib/coresight.sh ARGS="10" DATV="10" DATA="$DATD/perf-$TEST-$DATV.data" -- GitLab From a5f3171b13525d106e15286d96a9b53dcf7d4fd5 Mon Sep 17 00:00:00 2001 From: Athira Rajeev Date: Sun, 9 Jul 2023 23:57:52 +0530 Subject: [PATCH 0774/3445] perf tests lib probe_vfs_getname: Fix shellcheck warnings about missing shebang/local variables Running shellcheck on probe_vfs_getname fails with below warning: In ./tools/perf/tests/shell/lib/probe_vfs_getname.sh line 1: # Arnaldo Carvalho de Melo , 2017 ^-- SC2148 (error): Tips depend on target shell and yours is unknown. Add a shebang or a 'shell' directive. In ./tools/perf/tests/shell/lib/probe_vfs_getname.sh line 14: local verbose=$1 ^-----------^ SC3043 (warning): In POSIX sh, 'local' is undefined. Fix this: - by adding shebang in the beginning of the file and - rename variable verbose to "add_probe_verbose" after removing local Signed-off-by: Athira Rajeev Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Kajol Jain Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-19-atrajeev@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/lib/probe_vfs_getname.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/perf/tests/shell/lib/probe_vfs_getname.sh b/tools/perf/tests/shell/lib/probe_vfs_getname.sh index 60c5e34f90c41..bf4c1fb71c4b8 100644 --- a/tools/perf/tests/shell/lib/probe_vfs_getname.sh +++ b/tools/perf/tests/shell/lib/probe_vfs_getname.sh @@ -1,3 +1,4 @@ +#!/bin/sh # Arnaldo Carvalho de Melo , 2017 perf probe -l 2>&1 | grep -q probe:vfs_getname @@ -10,11 +11,11 @@ cleanup_probe_vfs_getname() { } add_probe_vfs_getname() { - local verbose=$1 + add_probe_verbose=$1 if [ $had_vfs_getname -eq 1 ] ; then line=$(perf probe -L getname_flags 2>&1 | grep -E 'result.*=.*filename;' | sed -r 's/[[:space:]]+([[:digit:]]+)[[:space:]]+result->uptr.*/\1/') perf probe -q "vfs_getname=getname_flags:${line} pathname=result->name:string" || \ - perf probe $verbose "vfs_getname=getname_flags:${line} pathname=filename:ustring" + perf probe $add_probe_verbose "vfs_getname=getname_flags:${line} pathname=filename:ustring" fi } -- GitLab From 1e094f925e1ec2825586b6a7c15f90afed9c1468 Mon Sep 17 00:00:00 2001 From: Athira Rajeev Date: Sun, 9 Jul 2023 23:57:53 +0530 Subject: [PATCH 0775/3445] perf tests lib waiting: Fix the shellcheck warnings about missing shebang Running shellcheck in "lib/waiting.sh" generates below warning: In ./tools/perf/tests/shell/lib/waiting.sh line 1: # SPDX-License-Identifier: GPL-2.0 ^-- SC2148 (error): Tips depend on target shell and yours is unknown. Add a shebang or a 'shell' directive. Fix this by adding shebang in the beginning of the script. Signed-off-by: Athira Rajeev Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Kajol Jain Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-20-atrajeev@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/lib/waiting.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/tests/shell/lib/waiting.sh b/tools/perf/tests/shell/lib/waiting.sh index e7a39134a68e8..bdd5a7c715910 100644 --- a/tools/perf/tests/shell/lib/waiting.sh +++ b/tools/perf/tests/shell/lib/waiting.sh @@ -1,3 +1,4 @@ +#!/bin/sh # SPDX-License-Identifier: GPL-2.0 tenths=date\ +%s%1N -- GitLab From 5e9310ae235bc304a522f14a7fce6293e3cb9d14 Mon Sep 17 00:00:00 2001 From: Athira Rajeev Date: Sun, 9 Jul 2023 23:57:54 +0530 Subject: [PATCH 0776/3445] perf trace x86_arch_prctl: Address shellcheck warnings about local variables Running shellcheck on x86_arch_prctl.sh generates below warning: In ./tools/perf/trace/beauty/x86_arch_prctl.sh line 10: local idx=$1 ^-------^ SC3043 (warning): In POSIX sh, 'local' is undefined. In ./tools/perf/trace/beauty/x86_arch_prctl.sh line 11: local prefix=$2 ^----------^ SC3043 (warning): In POSIX sh, 'local' is undefined. In ./tools/perf/trace/beauty/x86_arch_prctl.sh line 12: local first_entry=$3 ^---------------^ SC3043 (warning): In POSIX sh, 'local' is undefined. Fix this by removing local since these are variables used only in specific function Signed-off-by: Athira Rajeev Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Kajol Jain Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-21-atrajeev@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/trace/beauty/x86_arch_prctl.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/trace/beauty/x86_arch_prctl.sh b/tools/perf/trace/beauty/x86_arch_prctl.sh index fd5c740512c52..b1596df251f0a 100755 --- a/tools/perf/trace/beauty/x86_arch_prctl.sh +++ b/tools/perf/trace/beauty/x86_arch_prctl.sh @@ -7,9 +7,9 @@ prctl_arch_header=${x86_header_dir}/prctl.h print_range () { - local idx=$1 - local prefix=$2 - local first_entry=$3 + idx=$1 + prefix=$2 + first_entry=$3 printf "#define x86_arch_prctl_codes_%d_offset %s\n" $idx $first_entry printf "static const char *x86_arch_prctl_codes_%d[] = {\n" $idx -- GitLab From 84caba70d09c20638ee1ecdd24e0932520ad63fe Mon Sep 17 00:00:00 2001 From: Athira Rajeev Date: Sun, 9 Jul 2023 23:57:55 +0530 Subject: [PATCH 0777/3445] perf arch x86: Address shellcheck warnings about unused variables in syscalltbl.sh Running shellcheck on syscalltbl.sh generates below warning: In ./tools/perf/arch/x86/entry/syscalls/syscalltbl.sh line 27: while read nr abi name entry compat; do ^-^ SC2034 (warning): abi appears unused. Verify use (or export if used externally). ^----^ SC2034 (warning): compat appears unused. Verify use (or export if used externally). These variables are intentionally unused since they are needed to parse through the output. Use "_" as a prefix for these throw away variables. Signed-off-by: Athira Rajeev Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Kajol Jain Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-22-atrajeev@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/entry/syscalls/syscalltbl.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/arch/x86/entry/syscalls/syscalltbl.sh b/tools/perf/arch/x86/entry/syscalls/syscalltbl.sh index fa526a9938455..59d7914ed6bb0 100755 --- a/tools/perf/arch/x86/entry/syscalls/syscalltbl.sh +++ b/tools/perf/arch/x86/entry/syscalls/syscalltbl.sh @@ -24,7 +24,7 @@ sorted_table=$(mktemp /tmp/syscalltbl.XXXXXX) grep '^[0-9]' "$in" | sort -n > $sorted_table max_nr=0 -while read nr abi name entry compat; do +while read nr _abi name entry _compat; do if [ $nr -ge 512 ] ; then # discard compat sycalls break fi -- GitLab From 3a4367c11884a0be3a74963b37d2b2fe243ee1d4 Mon Sep 17 00:00:00 2001 From: Athira Rajeev Date: Sun, 9 Jul 2023 23:57:56 +0530 Subject: [PATCH 0778/3445] perf tests record+zstd_comp_decomp: Fix the shellcheck warnings about word splitting/quoting Running shellcheck on record+zstd_comp_decomp.sh testcases throws below warning: In tests/shell/record+zstd_comp_decomp.sh line 16: $perf_tool record -o $trace_file $gflag -z -F 5000 -- \ ^---------^ SC2086 (info): Double quote to prevent globbing and word splitting. Did you mean: $perf_tool record -o "$trace_file" $gflag -z -F 5000 -- \ In tests/shell/record+zstd_comp_decomp.sh line 22: $perf_tool report -i $trace_file --header --stats | \ ^---------^ SC2086 (info): Double quote to prevent globbing and word splitting. Added double quote around file names to fix these shellcheck reported issues. Signed-off-by: Athira Rajeev Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Kajol Jain Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-23-atrajeev@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/record+zstd_comp_decomp.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/perf/tests/shell/record+zstd_comp_decomp.sh b/tools/perf/tests/shell/record+zstd_comp_decomp.sh index 49bd875d51227..8929046e9057c 100755 --- a/tools/perf/tests/shell/record+zstd_comp_decomp.sh +++ b/tools/perf/tests/shell/record+zstd_comp_decomp.sh @@ -13,25 +13,25 @@ skip_if_no_z_record() { collect_z_record() { echo "Collecting compressed record file:" [ "$(uname -m)" != s390x ] && gflag='-g' - $perf_tool record -o $trace_file $gflag -z -F 5000 -- \ + $perf_tool record -o "$trace_file" $gflag -z -F 5000 -- \ dd count=500 if=/dev/urandom of=/dev/null } check_compressed_stats() { echo "Checking compressed events stats:" - $perf_tool report -i $trace_file --header --stats | \ + $perf_tool report -i "$trace_file" --header --stats | \ grep -E "(# compressed : Zstd,)|(COMPRESSED events:)" } check_compressed_output() { - $perf_tool inject -i $trace_file -o $trace_file.decomp && - $perf_tool report -i $trace_file --stdio -F comm,dso,sym | head -n -3 > $trace_file.comp.output && - $perf_tool report -i $trace_file.decomp --stdio -F comm,dso,sym | head -n -3 > $trace_file.decomp.output && - diff $trace_file.comp.output $trace_file.decomp.output + $perf_tool inject -i "$trace_file" -o "$trace_file.decomp" && + $perf_tool report -i "$trace_file" --stdio -F comm,dso,sym | head -n -3 > "$trace_file.comp.output" && + $perf_tool report -i "$trace_file.decomp" --stdio -F comm,dso,sym | head -n -3 > "$trace_file.decomp.output" && + diff "$trace_file.comp.output" "$trace_file.decomp.output" } skip_if_no_z_record || exit 2 collect_z_record && check_compressed_stats && check_compressed_output err=$? -rm -f $trace_file* +rm -f "$trace_file*" exit $err -- GitLab From 1f14b8af2c9c5ec43a834c960f436721253ff592 Mon Sep 17 00:00:00 2001 From: Kajol Jain Date: Sun, 9 Jul 2023 23:57:57 +0530 Subject: [PATCH 0779/3445] perf tests coresight thread_loop_check_tid_2: Fix shellcheck warnings about word splitting/quoting Running shellcheck on thread_loop_check_tid_2.sh throws below warning: In tests/shell/coresight/thread_loop_check_tid_2.sh line 8: . $(dirname $0)/../lib/coresight.sh ^-----------^ SC2046 (warning): Quote this to prevent word splitting. Fixed the warning by adding quotes to avoid word splitting. Signed-off-by: Kajol Jain Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-24-atrajeev@linux.vnet.ibm.com Signed-off-by: Athira Rajeev Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/coresight/thread_loop_check_tid_2.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/tests/shell/coresight/thread_loop_check_tid_2.sh b/tools/perf/tests/shell/coresight/thread_loop_check_tid_2.sh index a067145af43ce..6346fd5e87c8a 100755 --- a/tools/perf/tests/shell/coresight/thread_loop_check_tid_2.sh +++ b/tools/perf/tests/shell/coresight/thread_loop_check_tid_2.sh @@ -5,7 +5,7 @@ # Carsten Haitzler , 2021 TEST="thread_loop" -. $(dirname $0)/../lib/coresight.sh +. "$(dirname $0)"/../lib/coresight.sh ARGS="2 20" DATV="check-tid-2th" DATA="$DATD/perf-$TEST-$DATV.data" -- GitLab From eef1fb50caba2a4c508ffede6e98695c013ca1df Mon Sep 17 00:00:00 2001 From: Kajol Jain Date: Sun, 9 Jul 2023 23:57:58 +0530 Subject: [PATCH 0780/3445] perf tests lib stat_output: Fix shellcheck warning about missing shebang Running shellcheck on stat_output.sh throws below warning: In tests/shell/lib/stat_output.sh line 1: ^-- SC2148 (error): Tips depend on target shell and yours is unknown. Add a shebang or a 'shell' directive. Fixed the warning by adding shell directive. Signed-off-by: Kajol Jain Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-25-atrajeev@linux.vnet.ibm.com Signed-off-by: Athira Rajeev Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/lib/stat_output.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/tests/shell/lib/stat_output.sh b/tools/perf/tests/shell/lib/stat_output.sh index 698343f0ecf9b..3cc158a643269 100644 --- a/tools/perf/tests/shell/lib/stat_output.sh +++ b/tools/perf/tests/shell/lib/stat_output.sh @@ -1,3 +1,4 @@ +#!/bin/bash # SPDX-License-Identifier: GPL-2.0 # Return true if perf_event_paranoid is > $1 and not running as root. -- GitLab From 8439b44abb0c2e6522823e0e20ae21feb882b408 Mon Sep 17 00:00:00 2001 From: Athira Rajeev Date: Sun, 9 Jul 2023 23:57:59 +0530 Subject: [PATCH 0781/3445] perf tests stat+std_output: Fix shellcheck warnings about word splitting/quoting Running shellcheck on stat+csv_output.sh throws below warning: In tests/shell/stat+csv_output.sh line 9: . $(dirname $0)/lib/stat_output.sh ^-----------^ SC2046 (warning): Quote this to prevent word splitting. Fixed the warning by adding quotes to avoid word splitting. Signed-off-by: Athira Rajeev Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Kajol Jain Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-26-atrajeev@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/stat+csv_output.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/tests/shell/stat+csv_output.sh b/tools/perf/tests/shell/stat+csv_output.sh index 34a0701fee05e..d890eb26e914c 100755 --- a/tools/perf/tests/shell/stat+csv_output.sh +++ b/tools/perf/tests/shell/stat+csv_output.sh @@ -6,7 +6,7 @@ set -e -. $(dirname $0)/lib/stat_output.sh +. "$(dirname $0)"/lib/stat_output.sh csv_sep=@ -- GitLab From 35578a551b757cd00afe9b81406363f85cab16b2 Mon Sep 17 00:00:00 2001 From: Athira Rajeev Date: Sun, 9 Jul 2023 23:58:00 +0530 Subject: [PATCH 0782/3445] perf tests stat+std_output: Fix shellcheck warnings about word splitting/quoting and local variables Running shellcheck on stat_std_output testcase throws below warning: In tests/shell/stat+std_output.sh line 9: . $(dirname $0)/lib/stat_output.sh ^-----------^ SC2046 (warning): Quote this to prevent word splitting. In tests/shell/stat+std_output.sh line 32: local -i cnt=0 ^-^ SC2034 (warning): cnt appears unused. Verify use (or export if used externally). Fixed the warning by adding quotes to avoid word splitting and removed unused variable "cnt" at line 32. Signed-off-by: Athira Rajeev Acked-by: Ian Rogers Cc: Disha Goel Cc: Jiri Olsa Cc: Kajol Jain Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230709182800.53002-27-atrajeev@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/stat+std_output.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/perf/tests/shell/stat+std_output.sh b/tools/perf/tests/shell/stat+std_output.sh index f972b31fa0c27..fb2b10547a113 100755 --- a/tools/perf/tests/shell/stat+std_output.sh +++ b/tools/perf/tests/shell/stat+std_output.sh @@ -6,7 +6,7 @@ set -e -. $(dirname $0)/lib/stat_output.sh +. "$(dirname $0)"/lib/stat_output.sh stat_output=$(mktemp /tmp/__perf_test.stat_output.std.XXXXX) @@ -28,7 +28,6 @@ trap trap_cleanup EXIT TERM INT function commachecker() { - local -i cnt=0 local prefix=1 case "$1" -- GitLab From ed847e30f001b207013b6136c264454d7560557f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 1 Aug 2023 09:36:08 -0300 Subject: [PATCH 0783/3445] perf test bpf: Address error about non-null argument for epoll_pwait 2nd arg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First noticed on Fedora Rawhide: tests/bpf.c: In function ‘epoll_pwait_loop’: tests/bpf.c:36:17: error: argument 2 null where non-null expected [-Werror=nonnull] 36 | epoll_pwait(-(i + 1), NULL, 0, 0, NULL); | ^~~~~~~~~~~ In file included from tests/bpf.c:5: /usr/include/sys/epoll.h:134:12: note: in a call to function ‘epoll_pwait’ declared ‘nonnull’ 134 | extern int epoll_pwait (int __epfd, struct epoll_event *__events, | ^~~~~~~~~~~ [perfbuilder@27cfe44d67ed perf-6.5.0-rc2]$ gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/13/lto-wrapper OFFLOAD_TARGET_NAMES=nvptx-none OFFLOAD_TARGET_DEFAULT=1 Target: x86_64-redhat-linux Configured with: ../configure --enable-bootstrap --enable-languages=c,c++,fortran,objc,obj-c++,ada,go,d,m2,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-gcc-major-version-only --enable-libstdcxx-backtrace --with-libstdcxx-zoneinfo=/usr/share/zoneinfo --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --with-isl=/builddir/build/BUILD/gcc-13.2.1-20230728/obj-x86_64-redhat-linux/isl-install --enable-offload-targets=nvptx-none --without-cuda-driver --enable-offload-defaulted --enable-gnu-indirect-function --enable-cet --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux --with-build-config=bootstrap-lto --enable-link-serialization=1 Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 13.2.1 20230728 (Red Hat 13.2.1-1) (GCC) [perfbuilder@27cfe44d67ed perf-6.5.0-rc2]$ Just add that argument to address this compiler warning. Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/ZMj8+bvN86D0ZKiB@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/bpf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c index 31796f2a80f47..9ccecd873ecdd 100644 --- a/tools/perf/tests/bpf.c +++ b/tools/perf/tests/bpf.c @@ -29,11 +29,12 @@ static int epoll_pwait_loop(void) { + struct epoll_event events; int i; /* Should fail NR_ITERS times */ for (i = 0; i < NR_ITERS; i++) - epoll_pwait(-(i + 1), NULL, 0, 0, NULL); + epoll_pwait(-(i + 1), &events, 0, 0, NULL); return 0; } -- GitLab From e8ca4f0f8c03330bf912daee6aa258f4d33ee724 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 28 Jul 2023 23:19:30 +0900 Subject: [PATCH 0784/3445] perf probe: Show correct error message about @symbol usage for uprobe Since @symbol variable access is not supported by uprobe event, it must be correctly warn user instead of kernel version update. Committer testing: With/without the patch: [root@quaco ~]# perf probe -x ~/bin/perf -L sigtrap_handler 0 sigtrap_handler(int signum __maybe_unused, siginfo_t *info, void *ucontext __maybe_unused) 1 { 2 if (!__atomic_fetch_add(&ctx.signal_count, 1, __ATOMIC_RELAXED)) 3 ctx.first_siginfo = *info; 4 __atomic_fetch_sub(&ctx.tids_want_signal, syscall(SYS_gettid), __ATOMIC_RELAXED); 5 } static void *test_thread(void *arg) { [root@quaco ~]# perf probe -x ~/bin/perf sigtrap_handler:4 "ctx.signal_count" Without the patch: [root@quaco ~]# perf probe -x ~/bin/perf sigtrap_handler:4 "ctx.signal_count" Failed to write event: Invalid argument Please upgrade your kernel to at least 3.14 to have access to feature @ctx Error: Failed to add events. [root@quaco ~]# With the patch: [root@quaco ~]# Failed to write event: Invalid argument @ctx accesses a variable by symbol name, but that is not supported for user application probe. Error: Failed to add events. [root@quaco ~]# Reported-by: Arnaldo Carvalho de Melo Signed-off-by: Masami Hiramatsu Closes: https://lore.kernel.org/all/ZLWDEjvFjrrEJODp@kernel.org/ Tested-by: Arnaldo Carvalho de Melo Link: https://lore.kernel.org/r/169055397023.67089.12693645664676964310.stgit@devnote2 Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 16822a8a540ff..2d056f02ae408 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2800,13 +2800,18 @@ static void warn_uprobe_event_compat(struct probe_trace_event *tev) if (!tev->uprobes || tev->nargs == 0 || !buf) goto out; - for (i = 0; i < tev->nargs; i++) - if (strglobmatch(tev->args[i].value, "[$@+-]*")) { - pr_warning("Please upgrade your kernel to at least " - "3.14 to have access to feature %s\n", + for (i = 0; i < tev->nargs; i++) { + if (strchr(tev->args[i].value, '@')) { + pr_warning("%s accesses a variable by symbol name, but that is not supported for user application probe.\n", + tev->args[i].value); + break; + } + if (strglobmatch(tev->args[i].value, "[$+-]*")) { + pr_warning("Please upgrade your kernel to at least 3.14 to have access to feature %s\n", tev->args[i].value); break; } + } out: free(buf); } -- GitLab From 714b4511114254c9cf143dd31c4d4251129fb0a5 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 31 Jul 2023 22:36:31 -0700 Subject: [PATCH 0785/3445] perf parse-events x86: Avoid sorting uops_retired.slots As topdown.slots may appear as slots it may get confused with uops_retired.slots which is an invalid perf metric event group leader. Special case uops_retired.slots to avoid this confusion. Reviewed-by: Kan Liang Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Weilin Wang Cc: Xing Zhengjun Link: https://lore.kernel.org/r/20230801053634.1142634-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/util/evlist.c | 7 ++++--- tools/perf/arch/x86/util/evsel.c | 7 +++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/perf/arch/x86/util/evlist.c b/tools/perf/arch/x86/util/evlist.c index cbd5821829320..b1ce0c52d88da 100644 --- a/tools/perf/arch/x86/util/evlist.c +++ b/tools/perf/arch/x86/util/evlist.c @@ -75,11 +75,12 @@ int arch_evlist__add_default_attrs(struct evlist *evlist, int arch_evlist__cmp(const struct evsel *lhs, const struct evsel *rhs) { - if (topdown_sys_has_perf_metrics() && evsel__sys_has_perf_metrics(lhs)) { + if (topdown_sys_has_perf_metrics() && + (arch_evsel__must_be_in_group(lhs) || arch_evsel__must_be_in_group(rhs))) { /* Ensure the topdown slots comes first. */ - if (strcasestr(lhs->name, "slots")) + if (strcasestr(lhs->name, "slots") && !strcasestr(lhs->name, "uops_retired.slots")) return -1; - if (strcasestr(rhs->name, "slots")) + if (strcasestr(rhs->name, "slots") && !strcasestr(rhs->name, "uops_retired.slots")) return 1; /* Followed by topdown events. */ if (strcasestr(lhs->name, "topdown") && !strcasestr(rhs->name, "topdown")) diff --git a/tools/perf/arch/x86/util/evsel.c b/tools/perf/arch/x86/util/evsel.c index 81d22657922ac..090d0f371891f 100644 --- a/tools/perf/arch/x86/util/evsel.c +++ b/tools/perf/arch/x86/util/evsel.c @@ -40,12 +40,11 @@ bool evsel__sys_has_perf_metrics(const struct evsel *evsel) bool arch_evsel__must_be_in_group(const struct evsel *evsel) { - if (!evsel__sys_has_perf_metrics(evsel)) + if (!evsel__sys_has_perf_metrics(evsel) || !evsel->name || + strcasestr(evsel->name, "uops_retired.slots")) return false; - return evsel->name && - (strcasestr(evsel->name, "slots") || - strcasestr(evsel->name, "topdown")); + return strcasestr(evsel->name, "topdown") || strcasestr(evsel->name, "slots"); } int arch_evsel__hw_name(struct evsel *evsel, char *bf, size_t size) -- GitLab From ab0cfb796e03b24584bdb110111f1a290eb0df05 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 31 Jul 2023 22:36:32 -0700 Subject: [PATCH 0786/3445] perf vendor events intel: Update meteorlake to 1.04 1.04 events were released in: https://github.com/intel/perfmon/commit/44fe3681501f43fc515577aced8e944b187c8e51 Addition of 51 core events. Reviewed-by: Kan Liang Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Weilin Wang Cc: Xing Zhengjun Link: https://lore.kernel.org/r/20230801053634.1142634-3-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- .../pmu-events/arch/x86/meteorlake/cache.json | 165 ++++++++++++++++++ .../arch/x86/meteorlake/floating-point.json | 8 + .../arch/x86/meteorlake/frontend.json | 56 ++++++ .../arch/x86/meteorlake/memory.json | 80 +++++++++ .../pmu-events/arch/x86/meteorlake/other.json | 16 ++ .../arch/x86/meteorlake/pipeline.json | 159 +++++++++++++++++ 7 files changed, 485 insertions(+), 1 deletion(-) diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 6650100830c4e..9020d7a23c919 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -19,7 +19,7 @@ GenuineIntel-6-3A,v24,ivybridge,core GenuineIntel-6-3E,v23,ivytown,core GenuineIntel-6-2D,v23,jaketown,core GenuineIntel-6-(57|85),v10,knightslanding,core -GenuineIntel-6-A[AC],v1.03,meteorlake,core +GenuineIntel-6-A[AC],v1.04,meteorlake,core GenuineIntel-6-1[AEF],v3,nehalemep,core GenuineIntel-6-2E,v3,nehalemex,core GenuineIntel-6-A7,v1.01,rocketlake,core diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/cache.json b/tools/perf/pmu-events/arch/x86/meteorlake/cache.json index e1ae7c92f38e3..1de0200b32f6b 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/cache.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/cache.json @@ -36,6 +36,15 @@ "UMask": "0x2", "Unit": "cpu_core" }, + { + "BriefDescription": "Number of cycles a demand request has waited due to L1D due to lack of L2 resources.", + "EventCode": "0x48", + "EventName": "L1D_PEND_MISS.L2_STALLS", + "PublicDescription": "Counts number of cycles a demand request has waited due to L1D due to lack of L2 resources. Demand requests include cacheable/uncacheable demand load, store, lock or SW prefetch accesses.", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, { "BriefDescription": "Number of L1D misses that are outstanding", "EventCode": "0x48", @@ -260,6 +269,15 @@ "UMask": "0x40", "Unit": "cpu_core" }, + { + "BriefDescription": "Cycles when L1D is locked", + "EventCode": "0x42", + "EventName": "LOCK_CYCLES.CACHE_LOCK_DURATION", + "PublicDescription": "This event counts the number of cycles when the L1D is locked. It is a superset of the 0x1 mask (BUS_LOCK_CLOCKS.BUS_LOCK_DURATION).", + "SampleAfterValue": "2000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts the number of cacheable memory requests that miss in the LLC. Counts on a per core basis.", "EventCode": "0x2e", @@ -514,6 +532,17 @@ "UMask": "0x4", "Unit": "cpu_core" }, + { + "BriefDescription": "Retired load instructions whose data sources were L3 hit and cross-core snoop missed in on-pkg core cache.", + "Data_LA": "1", + "EventCode": "0xd2", + "EventName": "MEM_LOAD_L3_HIT_RETIRED.XSNP_MISS", + "PEBS": "1", + "PublicDescription": "Counts the retired load instructions whose data sources were L3 hit and cross-core snoop missed in on-pkg core cache.", + "SampleAfterValue": "20011", + "UMask": "0x1", + "Unit": "cpu_core" + }, { "BriefDescription": "Retired load instructions whose data sources were hits in L3 without snoops required", "Data_LA": "1", @@ -730,6 +759,14 @@ "UMask": "0x1", "Unit": "cpu_atom" }, + { + "BriefDescription": "MEM_STORE_RETIRED.L2_HIT", + "EventCode": "0x44", + "EventName": "MEM_STORE_RETIRED.L2_HIT", + "SampleAfterValue": "200003", + "UMask": "0x1", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts the number of load ops retired.", "Data_LA": "1", @@ -977,6 +1014,15 @@ "UMask": "0x8", "Unit": "cpu_core" }, + { + "BriefDescription": "Cacheable and Non-Cacheable code read requests", + "EventCode": "0x21", + "EventName": "OFFCORE_REQUESTS.DEMAND_CODE_RD", + "PublicDescription": "Counts both cacheable and Non-Cacheable code read requests.", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, { "BriefDescription": "Demand Data Read requests sent to uncore", "EventCode": "0x21", @@ -995,6 +1041,89 @@ "UMask": "0x4", "Unit": "cpu_core" }, + { + "BriefDescription": "Cycles when offcore outstanding cacheable Core Data Read transactions are present in SuperQueue (SQ), queue to uncore.", + "CounterMask": "1", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DATA_RD", + "PublicDescription": "Counts cycles when offcore outstanding cacheable Core Data Read transactions are present in the super queue. A transaction is considered to be in the Offcore outstanding state between L2 miss and transaction completion sent to requestor (SQ de-allocation). See corresponding Umask under OFFCORE_REQUESTS.", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles with offcore outstanding Code Reads transactions in the SuperQueue (SQ), queue to uncore.", + "CounterMask": "1", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_CODE_RD", + "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS.", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles where at least 1 outstanding demand data read request is pending.", + "CounterMask": "1", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_DATA_RD", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles with offcore outstanding demand rfo reads transactions in SuperQueue (SQ), queue to uncore.", + "CounterMask": "1", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_DEMAND_RFO", + "PublicDescription": "Counts the number of offcore outstanding demand rfo Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS.", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "OFFCORE_REQUESTS_OUTSTANDING.DATA_RD", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DATA_RD", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Offcore outstanding Code Reads transactions in the SuperQueue (SQ), queue to uncore, every cycle.", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_CODE_RD", + "PublicDescription": "Counts the number of offcore outstanding Code Reads transactions in the super queue every cycle. The 'Offcore outstanding' state of the transaction lasts from the L2 miss until the sending transaction completion to requestor (SQ deallocation). See the corresponding Umask under OFFCORE_REQUESTS.", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "For every cycle, increments by the number of outstanding demand data read requests pending.", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD", + "PublicDescription": "For every cycle, increments by the number of outstanding demand data read requests pending. Requests are considered outstanding from the time they miss the core's L2 cache until the transaction completion message is sent to the requestor.", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles with at least 6 offcore outstanding Demand Data Read transactions in uncore queue.", + "CounterMask": "6", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_DATA_RD_GE_6", + "SampleAfterValue": "2000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Store Read transactions pending for off-core. Highly correlated.", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.DEMAND_RFO", + "PublicDescription": "Counts the number of off-core outstanding read-for-ownership (RFO) store transactions every cycle. An RFO transaction is considered to be in the Off-core outstanding state between L2 cache miss and transaction completion.", + "SampleAfterValue": "1000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts bus locks, accounts for cache line split locks and UC locks.", "EventCode": "0x2c", @@ -1004,6 +1133,42 @@ "UMask": "0x10", "Unit": "cpu_core" }, + { + "BriefDescription": "Number of PREFETCHNTA instructions executed.", + "EventCode": "0x40", + "EventName": "SW_PREFETCH_ACCESS.NTA", + "PublicDescription": "Counts the number of PREFETCHNTA instructions executed.", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of PREFETCHW instructions executed.", + "EventCode": "0x40", + "EventName": "SW_PREFETCH_ACCESS.PREFETCHW", + "PublicDescription": "Counts the number of PREFETCHW instructions executed.", + "SampleAfterValue": "100003", + "UMask": "0x8", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of PREFETCHT0 instructions executed.", + "EventCode": "0x40", + "EventName": "SW_PREFETCH_ACCESS.T0", + "PublicDescription": "Counts the number of PREFETCHT0 instructions executed.", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Number of PREFETCHT1 or PREFETCHT2 instructions executed.", + "EventCode": "0x40", + "EventName": "SW_PREFETCH_ACCESS.T1_T2", + "PublicDescription": "Counts the number of PREFETCHT1 or PREFETCHT2 instructions executed.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts the number of issue slots every cycle that were not delivered by the frontend due to an icache miss", "EventCode": "0x71", diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/floating-point.json b/tools/perf/pmu-events/arch/x86/meteorlake/floating-point.json index 616489f0974a4..f66506ee37ef6 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/floating-point.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/floating-point.json @@ -41,6 +41,14 @@ "UMask": "0x2", "Unit": "cpu_core" }, + { + "BriefDescription": "FP_ARITH_DISPATCHED.PORT_5", + "EventCode": "0xb3", + "EventName": "FP_ARITH_DISPATCHED.PORT_5", + "SampleAfterValue": "2000003", + "UMask": "0x4", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.", "EventCode": "0xc7", diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/frontend.json b/tools/perf/pmu-events/arch/x86/meteorlake/frontend.json index 0f064518d1c0e..8264419500a50 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/frontend.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/frontend.json @@ -43,6 +43,14 @@ "UMask": "0x2", "Unit": "cpu_core" }, + { + "BriefDescription": "DSB_FILL.FB_STALL_OT", + "EventCode": "0x62", + "EventName": "DSB_FILL.FB_STALL_OT", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, { "BriefDescription": "Retired ANT branches", "EventCode": "0xc6", @@ -55,6 +63,30 @@ "UMask": "0x3", "Unit": "cpu_core" }, + { + "BriefDescription": "Retired Instructions who experienced DSB miss.", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.ANY_DSB_MISS", + "MSRIndex": "0x3F7", + "MSRValue": "0x1", + "PEBS": "1", + "PublicDescription": "Counts retired Instructions that experienced DSB (Decode stream buffer i.e. the decoded instruction-cache) miss.", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Retired Instructions who experienced a critical DSB miss.", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.DSB_MISS", + "MSRIndex": "0x3F7", + "MSRValue": "0x11", + "PEBS": "1", + "PublicDescription": "Number of retired Instructions that experienced a critical DSB (Decode stream buffer i.e. the decoded instruction-cache) miss. Critical means stalls were exposed to the back-end as a result of the DSB miss.", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts the number of instructions retired that were tagged because empty issue slots were seen before the uop due to ITLB miss", "EventCode": "0xc6", @@ -88,6 +120,18 @@ "UMask": "0x3", "Unit": "cpu_core" }, + { + "BriefDescription": "Retired Instructions who experienced Instruction L2 Cache true miss.", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.L2_MISS", + "MSRIndex": "0x3F7", + "MSRValue": "0x13", + "PEBS": "1", + "PublicDescription": "Counts retired Instructions who experienced Instruction L2 Cache true miss.", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, { "BriefDescription": "Retired instructions after front-end starvation of at least 1 cycle", "EventCode": "0xc6", @@ -243,6 +287,18 @@ "UMask": "0x3", "Unit": "cpu_core" }, + { + "BriefDescription": "Retired Instructions who experienced STLB (2nd level TLB) true miss.", + "EventCode": "0xc6", + "EventName": "FRONTEND_RETIRED.STLB_MISS", + "MSRIndex": "0x3F7", + "MSRValue": "0x15", + "PEBS": "1", + "PublicDescription": "Counts retired Instructions that experienced STLB (2nd level TLB) true miss.", + "SampleAfterValue": "100007", + "UMask": "0x3", + "Unit": "cpu_core" + }, { "BriefDescription": "FRONTEND_RETIRED.UNKNOWN_BRANCH", "EventCode": "0xc6", diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/memory.json b/tools/perf/pmu-events/arch/x86/meteorlake/memory.json index 67e949b4c7895..2605e1d0ba9f3 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/memory.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/memory.json @@ -66,6 +66,15 @@ "UMask": "0x84", "Unit": "cpu_atom" }, + { + "BriefDescription": "Number of machine clears due to memory ordering conflicts.", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.MEMORY_ORDERING", + "PublicDescription": "Counts the number of Machine Clears detected dye to memory ordering. Memory Ordering Machine Clears may apply when a memory read may not conform to the memory ordering rules of the x86 architecture", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, { "BriefDescription": "Execution stalls while L1 cache miss demand load is outstanding.", "CounterMask": "3", @@ -95,6 +104,35 @@ "UMask": "0x9", "Unit": "cpu_core" }, + { + "BriefDescription": "MEMORY_ORDERING.MD_NUKE", + "EventCode": "0x09", + "EventName": "MEMORY_ORDERING.MD_NUKE", + "SampleAfterValue": "100003", + "UMask": "0x1", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts the number of memory ordering machine clears due to memory renaming.", + "EventCode": "0x09", + "EventName": "MEMORY_ORDERING.MRN_NUKE", + "SampleAfterValue": "100003", + "UMask": "0x2", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 1024 cycles.", + "Data_LA": "1", + "EventCode": "0xcd", + "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_1024", + "MSRIndex": "0x3F6", + "MSRValue": "0x400", + "PEBS": "2", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 1024 cycles. Reported latency may be longer than just the memory latency.", + "SampleAfterValue": "53", + "UMask": "0x1", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 128 cycles.", "Data_LA": "1", @@ -121,6 +159,19 @@ "UMask": "0x1", "Unit": "cpu_core" }, + { + "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 2048 cycles.", + "Data_LA": "1", + "EventCode": "0xcd", + "EventName": "MEM_TRANS_RETIRED.LOAD_LATENCY_GT_2048", + "MSRIndex": "0x3F6", + "MSRValue": "0x800", + "PEBS": "2", + "PublicDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 2048 cycles. Reported latency may be longer than just the memory latency.", + "SampleAfterValue": "23", + "UMask": "0x1", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts randomly selected loads when the latency from first dispatch to completion is greater than 256 cycles.", "Data_LA": "1", @@ -235,5 +286,34 @@ "SampleAfterValue": "100003", "UMask": "0x10", "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles where data return is pending for a Demand Data Read request who miss L3 cache.", + "CounterMask": "1", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.CYCLES_WITH_L3_MISS_DEMAND_DATA_RD", + "PublicDescription": "Cycles with at least 1 Demand Data Read requests who miss L3 cache in the superQ.", + "SampleAfterValue": "1000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "For every cycle, increments by the number of demand data read requests pending that are known to have missed the L3 cache.", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.L3_MISS_DEMAND_DATA_RD", + "PublicDescription": "For every cycle, increments by the number of demand data read requests pending that are known to have missed the L3 cache. Note that this does not capture all elapsed cycles while requests are outstanding - only cycles from when the requests were known by the requesting core to have missed the L3 cache.", + "SampleAfterValue": "2000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Cycles where the core is waiting on at least 6 outstanding demand data read requests known to have missed the L3 cache.", + "CounterMask": "6", + "EventCode": "0x20", + "EventName": "OFFCORE_REQUESTS_OUTSTANDING.L3_MISS_DEMAND_DATA_RD_GE_6", + "PublicDescription": "Cycles where the core is waiting on at least 6 outstanding demand data read requests known to have missed the L3 cache. Note that this event does not capture all elapsed cycles while the requests are outstanding - only cycles from when the requests were known to have missed the L3 cache.", + "SampleAfterValue": "2000003", + "UMask": "0x10", + "Unit": "cpu_core" } ] diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/other.json b/tools/perf/pmu-events/arch/x86/meteorlake/other.json index 2ec57f487525e..f4c603599df49 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/other.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/other.json @@ -1,4 +1,12 @@ [ + { + "BriefDescription": "ASSISTS.PAGE_FAULT", + "EventCode": "0xc1", + "EventName": "ASSISTS.PAGE_FAULT", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts streaming stores that have any type of response.", "EventCode": "0x2A,0x2B", @@ -30,6 +38,14 @@ "UMask": "0x7", "Unit": "cpu_core" }, + { + "BriefDescription": "RS.EMPTY_RESOURCE", + "EventCode": "0xa5", + "EventName": "RS.EMPTY_RESOURCE", + "SampleAfterValue": "1000003", + "UMask": "0x1", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts the number of issue slots in a UMWAIT or TPAUSE instruction where no uop issues due to the instruction putting the CPU into the C0.1 activity state. For Tremont, UMWAIT and TPAUSE will only put the CPU into C0.1 activity state (not C0.2 activity state)", "EventCode": "0x75", diff --git a/tools/perf/pmu-events/arch/x86/meteorlake/pipeline.json b/tools/perf/pmu-events/arch/x86/meteorlake/pipeline.json index eeaa7a97f71cb..352c5efafc06d 100644 --- a/tools/perf/pmu-events/arch/x86/meteorlake/pipeline.json +++ b/tools/perf/pmu-events/arch/x86/meteorlake/pipeline.json @@ -311,6 +311,16 @@ "UMask": "0x60", "Unit": "cpu_core" }, + { + "BriefDescription": "This event counts the number of mispredicted ret instructions retired. Non PEBS", + "EventCode": "0xc5", + "EventName": "BR_MISP_RETIRED.RET", + "PEBS": "1", + "PublicDescription": "This is a non-precise version (that is, does not use PEBS) of the event that counts mispredicted return instructions retired.", + "SampleAfterValue": "100007", + "UMask": "0x8", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts the number of mispredicted near RET branch instructions retired.", "EventCode": "0xc5", @@ -329,6 +339,33 @@ "UMask": "0x48", "Unit": "cpu_core" }, + { + "BriefDescription": "Core clocks when the thread is in the C0.1 light-weight slower wakeup time but more power saving optimized state.", + "EventCode": "0xec", + "EventName": "CPU_CLK_UNHALTED.C01", + "PublicDescription": "Counts core clocks when the thread is in the C0.1 light-weight slower wakeup time but more power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions.", + "SampleAfterValue": "2000003", + "UMask": "0x10", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Core clocks when the thread is in the C0.2 light-weight faster wakeup time but less power saving optimized state.", + "EventCode": "0xec", + "EventName": "CPU_CLK_UNHALTED.C02", + "PublicDescription": "Counts core clocks when the thread is in the C0.2 light-weight faster wakeup time but less power saving optimized state. This state can be entered via the TPAUSE or UMWAIT instructions.", + "SampleAfterValue": "2000003", + "UMask": "0x20", + "Unit": "cpu_core" + }, + { + "BriefDescription": "Core clocks when the thread is in the C0.1 or C0.2 or running a PAUSE in C0 ACPI state.", + "EventCode": "0xec", + "EventName": "CPU_CLK_UNHALTED.C0_WAIT", + "PublicDescription": "Counts core clocks when the thread is in the C0.1 or C0.2 power saving optimized states (TPAUSE or UMWAIT instructions) or running the PAUSE instruction.", + "SampleAfterValue": "2000003", + "UMask": "0x70", + "Unit": "cpu_core" + }, { "BriefDescription": "Fixed Counter: Counts the number of unhalted core clock cycles", "EventName": "CPU_CLK_UNHALTED.CORE", @@ -361,6 +398,24 @@ "UMask": "0x2", "Unit": "cpu_core" }, + { + "BriefDescription": "CPU_CLK_UNHALTED.PAUSE", + "EventCode": "0xec", + "EventName": "CPU_CLK_UNHALTED.PAUSE", + "SampleAfterValue": "2000003", + "UMask": "0x40", + "Unit": "cpu_core" + }, + { + "BriefDescription": "CPU_CLK_UNHALTED.PAUSE_INST", + "CounterMask": "1", + "EdgeDetect": "1", + "EventCode": "0xec", + "EventName": "CPU_CLK_UNHALTED.PAUSE_INST", + "SampleAfterValue": "2000003", + "UMask": "0x40", + "Unit": "cpu_core" + }, { "BriefDescription": "Core crystal clock cycles. Cycle counts are evenly distributed between active threads in the Core.", "EventCode": "0x3c", @@ -602,6 +657,15 @@ "UMask": "0x10", "Unit": "cpu_core" }, + { + "BriefDescription": "Retired NOP instructions.", + "EventCode": "0xc0", + "EventName": "INST_RETIRED.NOP", + "PublicDescription": "Counts all retired NOP or ENDBR32/64 or PREFETCHIT0/1 instructions", + "SampleAfterValue": "2000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, { "BriefDescription": "Precise instruction retired with PEBS precise-distribution", "EventName": "INST_RETIRED.PREC_DIST", @@ -611,6 +675,15 @@ "UMask": "0x1", "Unit": "cpu_core" }, + { + "BriefDescription": "Iterations of Repeat string retired instructions.", + "EventCode": "0xc0", + "EventName": "INST_RETIRED.REP_ITERATION", + "PublicDescription": "Number of iterations of Repeat (REP) string retired instructions such as MOVS, CMPS, and SCAS. Each has a byte, word, and doubleword version and string instructions can be repeated using a repetition prefix, REP, that allows their architectural execution to be repeated a number of times as specified by the RCX register. Note the number of iterations is implementation-dependent.", + "SampleAfterValue": "2000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, { "BriefDescription": "Cycles the Backend cluster is recovering after a miss-speculation or a Store Buffer or Load Buffer drain stall.", "CounterMask": "1", @@ -621,6 +694,17 @@ "UMask": "0x3", "Unit": "cpu_core" }, + { + "BriefDescription": "Clears speculative count", + "CounterMask": "1", + "EdgeDetect": "1", + "EventCode": "0xad", + "EventName": "INT_MISC.CLEARS_COUNT", + "PublicDescription": "Counts the number of speculative clears due to any type of branch misprediction or machine clears", + "SampleAfterValue": "500009", + "UMask": "0x1", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts cycles after recovery from a branch misprediction or machine clear till the first uop is issued from the resteered path.", "EventCode": "0xad", @@ -630,6 +714,15 @@ "UMask": "0x80", "Unit": "cpu_core" }, + { + "BriefDescription": "Cycles when Resource Allocation Table (RAT) external stall is sent to Instruction Decode Queue (IDQ) for the thread", + "EventCode": "0xad", + "EventName": "INT_MISC.RAT_STALLS", + "PublicDescription": "This event counts the number of cycles during which Resource Allocation Table (RAT) external stall is sent to Instruction Decode Queue (IDQ) for the current thread. This also includes the cycles during which the Allocator is serving another thread.", + "SampleAfterValue": "1000003", + "UMask": "0x8", + "Unit": "cpu_core" + }, { "BriefDescription": "Core cycles the allocator was stalled due to recovery from earlier clear event for this thread", "EventCode": "0xad", @@ -733,6 +826,15 @@ "UMask": "0x4", "Unit": "cpu_atom" }, + { + "BriefDescription": "False dependencies in MOB due to partial compare on address.", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.ADDRESS_ALIAS", + "PublicDescription": "Counts the number of times a load got blocked due to false dependencies in MOB due to partial compare on address.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts the number of retired loads that are blocked because its address exactly matches an older store whose data is not ready.", "EventCode": "0x03", @@ -742,6 +844,15 @@ "UMask": "0x1", "Unit": "cpu_atom" }, + { + "BriefDescription": "The number of times that split load operations are temporarily blocked because all resources for handling the split accesses are in use.", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.NO_SR", + "PublicDescription": "Counts the number of times that split load operations are temporarily blocked because all resources for handling the split accesses are in use.", + "SampleAfterValue": "100003", + "UMask": "0x88", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts the number of retired loads that are blocked because its address partially overlapped with an older store.", "EventCode": "0x03", @@ -751,6 +862,15 @@ "UMask": "0x2", "Unit": "cpu_atom" }, + { + "BriefDescription": "Loads blocked due to overlapping with a preceding store that cannot be forwarded.", + "EventCode": "0x03", + "EventName": "LD_BLOCKS.STORE_FORWARD", + "PublicDescription": "Counts the number of times where store forwarding was prevented for a load operation. The most common case is a load blocked due to the address of memory access (partially) overlapping with a preceding uncompleted store. Note: See the table of not supported store forwards in the Optimization Guide.", + "SampleAfterValue": "100003", + "UMask": "0x82", + "Unit": "cpu_core" + }, { "BriefDescription": "Cycles Uops delivered by the LSD, but didn't come from the decoder.", "CounterMask": "1", @@ -823,6 +943,24 @@ "UMask": "0x1", "Unit": "cpu_atom" }, + { + "BriefDescription": "Self-modifying code (SMC) detected.", + "EventCode": "0xc3", + "EventName": "MACHINE_CLEARS.SMC", + "PublicDescription": "Counts self-modifying code (SMC) detected, which causes a machine clear.", + "SampleAfterValue": "100003", + "UMask": "0x4", + "Unit": "cpu_core" + }, + { + "BriefDescription": "LFENCE instructions retired", + "EventCode": "0xe0", + "EventName": "MISC2_RETIRED.LFENCE", + "PublicDescription": "number of LFENCE retired instructions", + "SampleAfterValue": "400009", + "UMask": "0x20", + "Unit": "cpu_core" + }, { "BriefDescription": "Counts cycles where the pipeline is stalled due to serializing operations.", "EventCode": "0xa2", @@ -1260,6 +1398,16 @@ "UMask": "0x1", "Unit": "cpu_core" }, + { + "BriefDescription": "Cycles with retired uop(s).", + "CounterMask": "1", + "EventCode": "0xc2", + "EventName": "UOPS_RETIRED.CYCLES", + "PublicDescription": "Counts cycles where at least one uop has retired.", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, { "BriefDescription": "Retired uops except the last uop of each instruction.", "EventCode": "0xc2", @@ -1306,6 +1454,17 @@ "UMask": "0x2", "Unit": "cpu_core" }, + { + "BriefDescription": "Cycles without actually retired uops.", + "CounterMask": "1", + "EventCode": "0xc2", + "EventName": "UOPS_RETIRED.STALLS", + "Invert": "1", + "PublicDescription": "This event counts cycles without actually retired uops.", + "SampleAfterValue": "1000003", + "UMask": "0x2", + "Unit": "cpu_core" + }, { "BriefDescription": "Cycles with less than 10 actually retired uops.", "CounterMask": "10", -- GitLab From b691f30700b56fe4fba690e17b1e1b2eb327a589 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 31 Jul 2023 22:36:33 -0700 Subject: [PATCH 0787/3445] perf vendor events intel: Update sapphirerapids to 1.15 1.15 events were released in: https://github.com/intel/perfmon/commit/76dfb81a1148ec049fd9caae9c62529404da63df Adds the events OCR.DEMAND_DATA_RD.LOCAL_SOCKET_PMM and OCR.DEMAND_DATA_RD.PMM. Reviewed-by: Kan Liang Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Weilin Wang Cc: Xing Zhengjun Link: https://lore.kernel.org/r/20230801053634.1142634-4-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/arch/x86/mapfile.csv | 2 +- .../arch/x86/sapphirerapids/other.json | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv index 9020d7a23c919..3a8770e29fe80 100644 --- a/tools/perf/pmu-events/arch/x86/mapfile.csv +++ b/tools/perf/pmu-events/arch/x86/mapfile.csv @@ -24,7 +24,7 @@ GenuineIntel-6-1[AEF],v3,nehalemep,core GenuineIntel-6-2E,v3,nehalemex,core GenuineIntel-6-A7,v1.01,rocketlake,core GenuineIntel-6-2A,v19,sandybridge,core -GenuineIntel-6-(8F|CF),v1.14,sapphirerapids,core +GenuineIntel-6-(8F|CF),v1.15,sapphirerapids,core GenuineIntel-6-AF,v1.00,sierraforest,core GenuineIntel-6-(37|4A|4C|4D|5A),v15,silvermont,core GenuineIntel-6-(4E|5E|8E|9E|A5|A6),v57,skylake,core diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/other.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/other.json index 31b6be9fb8c7a..442ef3807a9d0 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/other.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/other.json @@ -76,6 +76,24 @@ "SampleAfterValue": "100003", "UMask": "0x1" }, + { + "BriefDescription": "Counts demand data reads that were supplied by PMM attached to this socket, whether or not in Sub NUMA Cluster(SNC) Mode. In SNC Mode counts PMM accesses that are controlled by the close or distant SNC Cluster.", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.DEMAND_DATA_RD.LOCAL_SOCKET_PMM", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x700C00001", + "SampleAfterValue": "100003", + "UMask": "0x1" + }, + { + "BriefDescription": "Counts demand data reads that were supplied by PMM.", + "EventCode": "0x2A,0x2B", + "EventName": "OCR.DEMAND_DATA_RD.PMM", + "MSRIndex": "0x1a6,0x1a7", + "MSRValue": "0x703C00001", + "SampleAfterValue": "100003", + "UMask": "0x1" + }, { "BriefDescription": "Counts demand data reads that were supplied by DRAM attached to another socket.", "EventCode": "0x2A,0x2B", -- GitLab From 9a7d82c188baea8049e62cc1c92eb5b1846ed4ad Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 31 Jul 2023 22:36:34 -0700 Subject: [PATCH 0788/3445] perf vendor events intel: Update Icelake+ metric constraints Avoid grouping events especially in cases where the kernel's PMU driver fails to not open the events, causing the events to report back as "". This update comes from: https://github.com/intel/perfmon/pull/94 Fixes issues reported with patch: https://lore.kernel.org/lkml/20230719001836.198363-3-irogers@google.com/ Reviewed-by: Kan Liang Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Weilin Wang Cc: Xing Zhengjun Link: https://lore.kernel.org/r/20230801053634.1142634-5-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../pmu-events/arch/x86/alderlake/adl-metrics.json | 11 +++++++---- .../pmu-events/arch/x86/alderlaken/adln-metrics.json | 2 ++ .../perf/pmu-events/arch/x86/icelake/icl-metrics.json | 10 ++++++---- .../pmu-events/arch/x86/icelakex/icx-metrics.json | 10 ++++++---- .../pmu-events/arch/x86/rocketlake/rkl-metrics.json | 10 ++++++---- .../arch/x86/sapphirerapids/spr-metrics.json | 9 +++++---- .../pmu-events/arch/x86/tigerlake/tgl-metrics.json | 10 ++++++---- 7 files changed, 38 insertions(+), 24 deletions(-) diff --git a/tools/perf/pmu-events/arch/x86/alderlake/adl-metrics.json b/tools/perf/pmu-events/arch/x86/alderlake/adl-metrics.json index daf9458f0b77a..c6780d5c456ba 100644 --- a/tools/perf/pmu-events/arch/x86/alderlake/adl-metrics.json +++ b/tools/perf/pmu-events/arch/x86/alderlake/adl-metrics.json @@ -558,6 +558,7 @@ }, { "BriefDescription": "Counts the number of cycles a core is stalled due to a demand load which hit in the Last Level Cache (LLC) or other core with HITE/F/M.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "cpu_atom@MEM_BOUND_STALLS.LOAD_LLC_HIT@ / tma_info_core_clks - max((cpu_atom@MEM_BOUND_STALLS.LOAD@ - cpu_atom@LD_HEAD.L1_MISS_AT_RET@) / tma_info_core_clks, 0) * cpu_atom@MEM_BOUND_STALLS.LOAD_LLC_HIT@ / cpu_atom@MEM_BOUND_STALLS.LOAD@", "MetricGroup": "TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l3_bound", @@ -800,6 +801,7 @@ }, { "BriefDescription": "Counts the number of cycles that the oldest load of the load buffer is stalled at retirement due to a store forward block.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "LD_HEAD.ST_ADDR_AT_RET / tma_info_core_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_store_fwd_blk", @@ -1058,7 +1060,6 @@ }, { "BriefDescription": "This metric represents overall arithmetic floating-point (FP) operations fraction the CPU has executed (retired)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "tma_x87_use + tma_fp_scalar + tma_fp_vector", "MetricGroup": "HPC;TopdownL3;tma_L3_group;tma_light_operations_group", "MetricName": "tma_fp_arith", @@ -1230,6 +1231,7 @@ }, { "BriefDescription": "Total pipeline cost of Instruction Cache misses - subset of the Big_Code Bottleneck", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_fetch_latency * tma_icache_misses / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches))", "MetricGroup": "Fed;FetchLat;IcMiss;tma_issueFL", "MetricName": "tma_info_botlnk_l2_ic_misses", @@ -1267,6 +1269,7 @@ }, { "BriefDescription": "Total pipeline cost of (external) Memory Bandwidth related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full))) + tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_lock_latency + tma_split_loads + tma_store_fwd_blk))", "MetricGroup": "Mem;MemoryBW;Offcore;tma_issueBW", "MetricName": "tma_info_bottleneck_memory_bandwidth", @@ -1355,7 +1358,6 @@ }, { "BriefDescription": "Floating Point Operations Per Cycle", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(cpu_core@FP_ARITH_INST_RETIRED.SCALAR_SINGLE@ + cpu_core@FP_ARITH_INST_RETIRED.SCALAR_DOUBLE@ + 2 * cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE@ + 4 * (cpu_core@FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE@ + cpu_core@FP_ARITH_INST_RETIRED.256B_PACKED_DOUBLE@) + 8 * cpu_core@FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE@) / tma_info_core_core_clks", "MetricGroup": "Flops;Ret", "MetricName": "tma_info_core_flopc", @@ -1363,7 +1365,6 @@ }, { "BriefDescription": "Actual per-core usage of the Floating Point non-X87 execution units (regardless of precision or vector-width)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(cpu_core@FP_ARITH_DISPATCHED.PORT_0@ + cpu_core@FP_ARITH_DISPATCHED.PORT_1@ + cpu_core@FP_ARITH_DISPATCHED.PORT_5@) / (2 * tma_info_core_core_clks)", "MetricGroup": "Cor;Flops;HPC", "MetricName": "tma_info_core_fp_arith_utilization", @@ -1769,7 +1770,6 @@ }, { "BriefDescription": "Average number of Uops retired in cycles where at least one uop has retired.", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "tma_retiring * tma_info_thread_slots / cpu_core@UOPS_RETIRED.SLOTS\\,cmask\\=1@", "MetricGroup": "Pipeline;Ret", "MetricName": "tma_info_pipeline_retire", @@ -2002,6 +2002,7 @@ }, { "BriefDescription": "This metric estimates how often the CPU was stalled due to loads accesses to L3 cache or contended with a sibling Core", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(cpu_core@MEMORY_ACTIVITY.STALLS_L2_MISS@ - cpu_core@MEMORY_ACTIVITY.STALLS_L3_MISS@) / tma_info_thread_clks", "MetricGroup": "CacheMisses;MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l3_bound", @@ -2375,6 +2376,7 @@ }, { "BriefDescription": "This metric represents rate of split store accesses", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "MEM_INST_RETIRED.SPLIT_STORES / tma_info_core_core_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_issueSpSt;tma_store_bound_group", "MetricName": "tma_split_stores", @@ -2405,6 +2407,7 @@ }, { "BriefDescription": "This metric roughly estimates fraction of cycles when the memory subsystem had loads blocked since they could not forward data from earlier (in program order) overlapping stores", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "13 * cpu_core@LD_BLOCKS.STORE_FORWARD@ / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_store_fwd_blk", diff --git a/tools/perf/pmu-events/arch/x86/alderlaken/adln-metrics.json b/tools/perf/pmu-events/arch/x86/alderlaken/adln-metrics.json index 0f1628d698da9..06e67e34e1bfb 100644 --- a/tools/perf/pmu-events/arch/x86/alderlaken/adln-metrics.json +++ b/tools/perf/pmu-events/arch/x86/alderlaken/adln-metrics.json @@ -466,6 +466,7 @@ }, { "BriefDescription": "Counts the number of cycles a core is stalled due to a demand load which hit in the Last Level Cache (LLC) or other core with HITE/F/M.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "MEM_BOUND_STALLS.LOAD_LLC_HIT / tma_info_core_clks - max((MEM_BOUND_STALLS.LOAD - LD_HEAD.L1_MISS_AT_RET) / tma_info_core_clks, 0) * MEM_BOUND_STALLS.LOAD_LLC_HIT / MEM_BOUND_STALLS.LOAD", "MetricGroup": "TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l3_bound", @@ -682,6 +683,7 @@ }, { "BriefDescription": "Counts the number of cycles that the oldest load of the load buffer is stalled at retirement due to a store forward block.", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "LD_HEAD.ST_ADDR_AT_RET / tma_info_core_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_store_fwd_blk", diff --git a/tools/perf/pmu-events/arch/x86/icelake/icl-metrics.json b/tools/perf/pmu-events/arch/x86/icelake/icl-metrics.json index 8fcc05c4e0a1d..a6eed0d9a26da 100644 --- a/tools/perf/pmu-events/arch/x86/icelake/icl-metrics.json +++ b/tools/perf/pmu-events/arch/x86/icelake/icl-metrics.json @@ -85,6 +85,7 @@ }, { "BriefDescription": "This metric estimates how often memory load accesses were aliased by preceding stores (in program order) with a 4K address offset", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "LD_BLOCKS_PARTIAL.ADDRESS_ALIAS / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_4k_aliasing", @@ -319,7 +320,6 @@ }, { "BriefDescription": "This metric represents overall arithmetic floating-point (FP) operations fraction the CPU has executed (retired)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "tma_x87_use + tma_fp_scalar + tma_fp_vector", "MetricGroup": "HPC;TopdownL3;tma_L3_group;tma_light_operations_group", "MetricName": "tma_fp_arith", @@ -464,6 +464,7 @@ }, { "BriefDescription": "Total pipeline cost of Instruction Cache misses - subset of the Big_Code Bottleneck", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_fetch_latency * tma_icache_misses / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches))", "MetricGroup": "Fed;FetchLat;IcMiss;tma_issueFL", "MetricName": "tma_info_botlnk_l2_ic_misses", @@ -497,6 +498,7 @@ }, { "BriefDescription": "Total pipeline cost of (external) Memory Bandwidth related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full))) + tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_fb_full / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_lock_latency + tma_split_loads + tma_store_fwd_blk))", "MetricGroup": "Mem;MemoryBW;Offcore;tma_issueBW", "MetricName": "tma_info_bottleneck_memory_bandwidth", @@ -574,14 +576,12 @@ }, { "BriefDescription": "Floating Point Operations Per Cycle", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(cpu@FP_ARITH_INST_RETIRED.SCALAR_SINGLE\\,umask\\=0x03@ + 2 * FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE + 4 * cpu@FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE\\,umask\\=0x18@ + 8 * cpu@FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE\\,umask\\=0x60@ + 16 * FP_ARITH_INST_RETIRED.512B_PACKED_SINGLE) / tma_info_core_core_clks", "MetricGroup": "Flops;Ret", "MetricName": "tma_info_core_flopc" }, { "BriefDescription": "Actual per-core usage of the Floating Point non-X87 execution units (regardless of precision or vector-width)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(cpu@FP_ARITH_INST_RETIRED.SCALAR_SINGLE\\,umask\\=0x03@ + cpu@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE\\,umask\\=0xfc@) / (2 * tma_info_core_core_clks)", "MetricGroup": "Cor;Flops;HPC", "MetricName": "tma_info_core_fp_arith_utilization", @@ -927,7 +927,6 @@ }, { "BriefDescription": "Average number of Uops retired in cycles where at least one uop has retired.", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "tma_retiring * tma_info_thread_slots / cpu@UOPS_RETIRED.SLOTS\\,cmask\\=1@", "MetricGroup": "Pipeline;Ret", "MetricName": "tma_info_pipeline_retire" @@ -1100,6 +1099,7 @@ }, { "BriefDescription": "This metric estimates how often the CPU was stalled due to loads accesses to L3 cache or contended with a sibling Core", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(CYCLE_ACTIVITY.STALLS_L2_MISS - CYCLE_ACTIVITY.STALLS_L3_MISS) / tma_info_thread_clks", "MetricGroup": "CacheMisses;MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l3_bound", @@ -1419,6 +1419,7 @@ }, { "BriefDescription": "This metric represents rate of split store accesses", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "MEM_INST_RETIRED.SPLIT_STORES / tma_info_core_core_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_issueSpSt;tma_store_bound_group", "MetricName": "tma_split_stores", @@ -1446,6 +1447,7 @@ }, { "BriefDescription": "This metric roughly estimates fraction of cycles when the memory subsystem had loads blocked since they could not forward data from earlier (in program order) overlapping stores", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "13 * LD_BLOCKS.STORE_FORWARD / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_store_fwd_blk", diff --git a/tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json b/tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json index 9bb7e3f20f7f5..7082ad5ba9613 100644 --- a/tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json +++ b/tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json @@ -289,6 +289,7 @@ }, { "BriefDescription": "This metric estimates how often memory load accesses were aliased by preceding stores (in program order) with a 4K address offset", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "LD_BLOCKS_PARTIAL.ADDRESS_ALIAS / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_4k_aliasing", @@ -523,7 +524,6 @@ }, { "BriefDescription": "This metric represents overall arithmetic floating-point (FP) operations fraction the CPU has executed (retired)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "tma_x87_use + tma_fp_scalar + tma_fp_vector", "MetricGroup": "HPC;TopdownL3;tma_L3_group;tma_light_operations_group", "MetricName": "tma_fp_arith", @@ -668,6 +668,7 @@ }, { "BriefDescription": "Total pipeline cost of Instruction Cache misses - subset of the Big_Code Bottleneck", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_fetch_latency * tma_icache_misses / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches))", "MetricGroup": "Fed;FetchLat;IcMiss;tma_issueFL", "MetricName": "tma_info_botlnk_l2_ic_misses", @@ -701,6 +702,7 @@ }, { "BriefDescription": "Total pipeline cost of (external) Memory Bandwidth related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_pmm_bound + tma_store_bound) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_pmm_bound + tma_store_bound) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full))) + tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_pmm_bound + tma_store_bound) * (tma_fb_full / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_lock_latency + tma_split_loads + tma_store_fwd_blk))", "MetricGroup": "Mem;MemoryBW;Offcore;tma_issueBW", "MetricName": "tma_info_bottleneck_memory_bandwidth", @@ -778,14 +780,12 @@ }, { "BriefDescription": "Floating Point Operations Per Cycle", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(cpu@FP_ARITH_INST_RETIRED.SCALAR_SINGLE\\,umask\\=0x03@ + 2 * FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE + 4 * cpu@FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE\\,umask\\=0x18@ + 8 * cpu@FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE\\,umask\\=0x60@ + 16 * FP_ARITH_INST_RETIRED.512B_PACKED_SINGLE) / tma_info_core_core_clks", "MetricGroup": "Flops;Ret", "MetricName": "tma_info_core_flopc" }, { "BriefDescription": "Actual per-core usage of the Floating Point non-X87 execution units (regardless of precision or vector-width)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(cpu@FP_ARITH_INST_RETIRED.SCALAR_SINGLE\\,umask\\=0x03@ + cpu@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE\\,umask\\=0xfc@) / (2 * tma_info_core_core_clks)", "MetricGroup": "Cor;Flops;HPC", "MetricName": "tma_info_core_fp_arith_utilization", @@ -1144,7 +1144,6 @@ }, { "BriefDescription": "Average number of Uops retired in cycles where at least one uop has retired.", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "tma_retiring * tma_info_thread_slots / cpu@UOPS_RETIRED.SLOTS\\,cmask\\=1@", "MetricGroup": "Pipeline;Ret", "MetricName": "tma_info_pipeline_retire" @@ -1369,6 +1368,7 @@ }, { "BriefDescription": "This metric estimates how often the CPU was stalled due to loads accesses to L3 cache or contended with a sibling Core", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(CYCLE_ACTIVITY.STALLS_L2_MISS - CYCLE_ACTIVITY.STALLS_L3_MISS) / tma_info_thread_clks", "MetricGroup": "CacheMisses;MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l3_bound", @@ -1715,6 +1715,7 @@ }, { "BriefDescription": "This metric represents rate of split store accesses", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "MEM_INST_RETIRED.SPLIT_STORES / tma_info_core_core_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_issueSpSt;tma_store_bound_group", "MetricName": "tma_split_stores", @@ -1742,6 +1743,7 @@ }, { "BriefDescription": "This metric roughly estimates fraction of cycles when the memory subsystem had loads blocked since they could not forward data from earlier (in program order) overlapping stores", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "13 * LD_BLOCKS.STORE_FORWARD / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_store_fwd_blk", diff --git a/tools/perf/pmu-events/arch/x86/rocketlake/rkl-metrics.json b/tools/perf/pmu-events/arch/x86/rocketlake/rkl-metrics.json index 1bb9cededa561..a0191c8b708d1 100644 --- a/tools/perf/pmu-events/arch/x86/rocketlake/rkl-metrics.json +++ b/tools/perf/pmu-events/arch/x86/rocketlake/rkl-metrics.json @@ -85,6 +85,7 @@ }, { "BriefDescription": "This metric estimates how often memory load accesses were aliased by preceding stores (in program order) with a 4K address offset", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "LD_BLOCKS_PARTIAL.ADDRESS_ALIAS / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_4k_aliasing", @@ -319,7 +320,6 @@ }, { "BriefDescription": "This metric represents overall arithmetic floating-point (FP) operations fraction the CPU has executed (retired)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "tma_x87_use + tma_fp_scalar + tma_fp_vector", "MetricGroup": "HPC;TopdownL3;tma_L3_group;tma_light_operations_group", "MetricName": "tma_fp_arith", @@ -464,6 +464,7 @@ }, { "BriefDescription": "Total pipeline cost of Instruction Cache misses - subset of the Big_Code Bottleneck", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_fetch_latency * tma_icache_misses / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches))", "MetricGroup": "Fed;FetchLat;IcMiss;tma_issueFL", "MetricName": "tma_info_botlnk_l2_ic_misses", @@ -497,6 +498,7 @@ }, { "BriefDescription": "Total pipeline cost of (external) Memory Bandwidth related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full))) + tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_fb_full / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_lock_latency + tma_split_loads + tma_store_fwd_blk))", "MetricGroup": "Mem;MemoryBW;Offcore;tma_issueBW", "MetricName": "tma_info_bottleneck_memory_bandwidth", @@ -574,14 +576,12 @@ }, { "BriefDescription": "Floating Point Operations Per Cycle", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(cpu@FP_ARITH_INST_RETIRED.SCALAR_SINGLE\\,umask\\=0x03@ + 2 * FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE + 4 * cpu@FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE\\,umask\\=0x18@ + 8 * cpu@FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE\\,umask\\=0x60@ + 16 * FP_ARITH_INST_RETIRED.512B_PACKED_SINGLE) / tma_info_core_core_clks", "MetricGroup": "Flops;Ret", "MetricName": "tma_info_core_flopc" }, { "BriefDescription": "Actual per-core usage of the Floating Point non-X87 execution units (regardless of precision or vector-width)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(cpu@FP_ARITH_INST_RETIRED.SCALAR_SINGLE\\,umask\\=0x03@ + cpu@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE\\,umask\\=0xfc@) / (2 * tma_info_core_core_clks)", "MetricGroup": "Cor;Flops;HPC", "MetricName": "tma_info_core_fp_arith_utilization", @@ -933,7 +933,6 @@ }, { "BriefDescription": "Average number of Uops retired in cycles where at least one uop has retired.", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "tma_retiring * tma_info_thread_slots / cpu@UOPS_RETIRED.SLOTS\\,cmask\\=1@", "MetricGroup": "Pipeline;Ret", "MetricName": "tma_info_pipeline_retire" @@ -1126,6 +1125,7 @@ }, { "BriefDescription": "This metric estimates how often the CPU was stalled due to loads accesses to L3 cache or contended with a sibling Core", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(CYCLE_ACTIVITY.STALLS_L2_MISS - CYCLE_ACTIVITY.STALLS_L3_MISS) / tma_info_thread_clks", "MetricGroup": "CacheMisses;MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l3_bound", @@ -1445,6 +1445,7 @@ }, { "BriefDescription": "This metric represents rate of split store accesses", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "MEM_INST_RETIRED.SPLIT_STORES / tma_info_core_core_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_issueSpSt;tma_store_bound_group", "MetricName": "tma_split_stores", @@ -1472,6 +1473,7 @@ }, { "BriefDescription": "This metric roughly estimates fraction of cycles when the memory subsystem had loads blocked since they could not forward data from earlier (in program order) overlapping stores", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "13 * LD_BLOCKS.STORE_FORWARD / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_store_fwd_blk", diff --git a/tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json b/tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json index c207c851a9f98..222212abd811c 100644 --- a/tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json +++ b/tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json @@ -553,7 +553,6 @@ }, { "BriefDescription": "This metric represents overall arithmetic floating-point (FP) operations fraction the CPU has executed (retired)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "tma_x87_use + tma_fp_scalar + tma_fp_vector + tma_fp_amx", "MetricGroup": "HPC;TopdownL3;tma_L3_group;tma_light_operations_group", "MetricName": "tma_fp_arith", @@ -717,6 +716,7 @@ }, { "BriefDescription": "Total pipeline cost of Instruction Cache misses - subset of the Big_Code Bottleneck", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_fetch_latency * tma_icache_misses / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches))", "MetricGroup": "Fed;FetchLat;IcMiss;tma_issueFL", "MetricName": "tma_info_botlnk_l2_ic_misses", @@ -750,6 +750,7 @@ }, { "BriefDescription": "Total pipeline cost of (external) Memory Bandwidth related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_pmm_bound + tma_store_bound) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_pmm_bound + tma_store_bound) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full))) + tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_pmm_bound + tma_store_bound) * (tma_fb_full / (tma_dtlb_load + tma_fb_full + tma_lock_latency + tma_split_loads + tma_store_fwd_blk))", "MetricGroup": "Mem;MemoryBW;Offcore;tma_issueBW", "MetricName": "tma_info_bottleneck_memory_bandwidth", @@ -827,14 +828,12 @@ }, { "BriefDescription": "Floating Point Operations Per Cycle", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "cpu@FP_ARITH_INST_RETIRED.SCALAR_SINGLE\\,umask\\=0x03@ + FP_ARITH_INST_RETIRED2.SCALAR_HALF + 2 * (FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE + FP_ARITH_INST_RETIRED2.COMPLEX_SCALAR_HALF) + 4 * cpu@FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE\\,umask\\=0x18@ + 8 * (FP_ARITH_INST_RETIRED2.128B_PACKED_HALF + cpu@FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE\\,umask\\=0x60@) + 16 * (FP_ARITH_INST_RETIRED2.256B_PACKED_HALF + FP_ARITH_INST_RETIRED.512B_PACKED_SINGLE) + 32 * FP_ARITH_INST_RETIRED2.512B_PACKED_HALF + 4 * AMX_OPS_RETIRED.BF16", "MetricGroup": "Flops;Ret", "MetricName": "tma_info_core_flopc" }, { "BriefDescription": "Actual per-core usage of the Floating Point non-X87 execution units (regardless of precision or vector-width)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(FP_ARITH_DISPATCHED.PORT_0 + FP_ARITH_DISPATCHED.PORT_1 + FP_ARITH_DISPATCHED.PORT_5) / (2 * tma_info_core_core_clks)", "MetricGroup": "Cor;Flops;HPC", "MetricName": "tma_info_core_fp_arith_utilization", @@ -1216,7 +1215,6 @@ }, { "BriefDescription": "Average number of Uops retired in cycles where at least one uop has retired.", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "tma_retiring * tma_info_thread_slots / cpu@UOPS_RETIRED.SLOTS\\,cmask\\=1@", "MetricGroup": "Pipeline;Ret", "MetricName": "tma_info_pipeline_retire" @@ -1467,6 +1465,7 @@ }, { "BriefDescription": "This metric estimates how often the CPU was stalled due to loads accesses to L3 cache or contended with a sibling Core", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(MEMORY_ACTIVITY.STALLS_L2_MISS - MEMORY_ACTIVITY.STALLS_L3_MISS) / tma_info_thread_clks", "MetricGroup": "CacheMisses;MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l3_bound", @@ -1841,6 +1840,7 @@ }, { "BriefDescription": "This metric represents rate of split store accesses", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "MEM_INST_RETIRED.SPLIT_STORES / tma_info_core_core_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_issueSpSt;tma_store_bound_group", "MetricName": "tma_split_stores", @@ -1868,6 +1868,7 @@ }, { "BriefDescription": "This metric roughly estimates fraction of cycles when the memory subsystem had loads blocked since they could not forward data from earlier (in program order) overlapping stores", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "13 * LD_BLOCKS.STORE_FORWARD / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_store_fwd_blk", diff --git a/tools/perf/pmu-events/arch/x86/tigerlake/tgl-metrics.json b/tools/perf/pmu-events/arch/x86/tigerlake/tgl-metrics.json index c7c2d6ab1a934..fab084e1bc69a 100644 --- a/tools/perf/pmu-events/arch/x86/tigerlake/tgl-metrics.json +++ b/tools/perf/pmu-events/arch/x86/tigerlake/tgl-metrics.json @@ -79,6 +79,7 @@ }, { "BriefDescription": "This metric estimates how often memory load accesses were aliased by preceding stores (in program order) with a 4K address offset", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "LD_BLOCKS_PARTIAL.ADDRESS_ALIAS / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_4k_aliasing", @@ -313,7 +314,6 @@ }, { "BriefDescription": "This metric represents overall arithmetic floating-point (FP) operations fraction the CPU has executed (retired)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "tma_x87_use + tma_fp_scalar + tma_fp_vector", "MetricGroup": "HPC;TopdownL3;tma_L3_group;tma_light_operations_group", "MetricName": "tma_fp_arith", @@ -458,6 +458,7 @@ }, { "BriefDescription": "Total pipeline cost of Instruction Cache misses - subset of the Big_Code Bottleneck", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * (tma_fetch_latency * tma_icache_misses / (tma_branch_resteers + tma_dsb_switches + tma_icache_misses + tma_itlb_misses + tma_lcp + tma_ms_switches))", "MetricGroup": "Fed;FetchLat;IcMiss;tma_issueFL", "MetricName": "tma_info_botlnk_l2_ic_misses", @@ -491,6 +492,7 @@ }, { "BriefDescription": "Total pipeline cost of (external) Memory Bandwidth related bottlenecks", + "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "100 * tma_memory_bound * (tma_dram_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_mem_bandwidth / (tma_mem_bandwidth + tma_mem_latency)) + tma_l3_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_sq_full / (tma_contested_accesses + tma_data_sharing + tma_l3_hit_latency + tma_sq_full))) + tma_l1_bound / (tma_dram_bound + tma_l1_bound + tma_l2_bound + tma_l3_bound + tma_store_bound) * (tma_fb_full / (tma_4k_aliasing + tma_dtlb_load + tma_fb_full + tma_lock_latency + tma_split_loads + tma_store_fwd_blk))", "MetricGroup": "Mem;MemoryBW;Offcore;tma_issueBW", "MetricName": "tma_info_bottleneck_memory_bandwidth", @@ -568,14 +570,12 @@ }, { "BriefDescription": "Floating Point Operations Per Cycle", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(cpu@FP_ARITH_INST_RETIRED.SCALAR_SINGLE\\,umask\\=0x03@ + 2 * FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE + 4 * cpu@FP_ARITH_INST_RETIRED.128B_PACKED_SINGLE\\,umask\\=0x18@ + 8 * cpu@FP_ARITH_INST_RETIRED.256B_PACKED_SINGLE\\,umask\\=0x60@ + 16 * FP_ARITH_INST_RETIRED.512B_PACKED_SINGLE) / tma_info_core_core_clks", "MetricGroup": "Flops;Ret", "MetricName": "tma_info_core_flopc" }, { "BriefDescription": "Actual per-core usage of the Floating Point non-X87 execution units (regardless of precision or vector-width)", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "(cpu@FP_ARITH_INST_RETIRED.SCALAR_SINGLE\\,umask\\=0x03@ + cpu@FP_ARITH_INST_RETIRED.128B_PACKED_DOUBLE\\,umask\\=0xfc@) / (2 * tma_info_core_core_clks)", "MetricGroup": "Cor;Flops;HPC", "MetricName": "tma_info_core_fp_arith_utilization", @@ -927,7 +927,6 @@ }, { "BriefDescription": "Average number of Uops retired in cycles where at least one uop has retired.", - "MetricConstraint": "NO_GROUP_EVENTS", "MetricExpr": "tma_retiring * tma_info_thread_slots / cpu@UOPS_RETIRED.SLOTS\\,cmask\\=1@", "MetricGroup": "Pipeline;Ret", "MetricName": "tma_info_pipeline_retire" @@ -1114,6 +1113,7 @@ }, { "BriefDescription": "This metric estimates how often the CPU was stalled due to loads accesses to L3 cache or contended with a sibling Core", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "(CYCLE_ACTIVITY.STALLS_L2_MISS - CYCLE_ACTIVITY.STALLS_L3_MISS) / tma_info_thread_clks", "MetricGroup": "CacheMisses;MemoryBound;TmaL3mem;TopdownL3;tma_L3_group;tma_memory_bound_group", "MetricName": "tma_l3_bound", @@ -1433,6 +1433,7 @@ }, { "BriefDescription": "This metric represents rate of split store accesses", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "MEM_INST_RETIRED.SPLIT_STORES / tma_info_core_core_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_issueSpSt;tma_store_bound_group", "MetricName": "tma_split_stores", @@ -1460,6 +1461,7 @@ }, { "BriefDescription": "This metric roughly estimates fraction of cycles when the memory subsystem had loads blocked since they could not forward data from earlier (in program order) overlapping stores", + "MetricConstraint": "NO_GROUP_EVENTS_NMI", "MetricExpr": "13 * LD_BLOCKS.STORE_FORWARD / tma_info_thread_clks", "MetricGroup": "TopdownL4;tma_L4_group;tma_l1_bound_group", "MetricName": "tma_store_fwd_blk", -- GitLab From a7789d3f2e96ac1056f127d529f9c35e3ce88479 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 2 Aug 2023 10:33:42 -0300 Subject: [PATCH 0789/3445] perf python: Cope with declarations after statements found in Python.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With -Werror the build was failing on fedora rawhide: [perfbuilder@27cfe44d67ed perf-6.5.0-rc2]$ gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/13/lto-wrapper OFFLOAD_TARGET_NAMES=nvptx-none OFFLOAD_TARGET_DEFAULT=1 Target: x86_64-redhat-linux Configured with: ../configure --enable-bootstrap --enable-languages=c,c++,fortran,objc,obj-c++,ada,go,d,m2,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-gcc-major-version-only --enable-libstdcxx-backtrace --with-libstdcxx-zoneinfo=/usr/share/zoneinfo --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --with-isl=/builddir/build/BUILD/gcc-13.2.1-20230728/obj-x86_64-redhat-linux/isl-install --enable-offload-targets=nvptx-none --without-cuda-driver --enable-offload-defaulted --enable-gnu-indirect-function --enable-cet --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux --with-build-config=bootstrap-lto --enable-link-serialization=1 Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 13.2.1 20230728 (Red Hat 13.2.1-1) (GCC) [perfbuilder@27cfe44d67ed perf-6.5.0-rc2]$ In file included from /usr/include/python3.12/Python.h:44, from /git/perf-6.5.0-rc2/tools/perf/util/python.c:2: /usr/include/python3.12/object.h: In function ‘Py_SIZE’: /usr/include/python3.12/object.h:217:5: error: ISO C90 forbids mixed declarations and code [-Werror=declaration-after-statement] 217 | PyVarObject *var_ob = _PyVarObject_CAST(ob); | ^~~~~~~~~~~ LD /tmp/build/perf/arch/perf-in.o In file included from /usr/include/python3.12/Python.h:53: /usr/include/python3.12/cpython/longintrepr.h: In function ‘_PyLong_CompactValue’: /usr/include/python3.12/cpython/longintrepr.h:121:5: error: ISO C90 forbids mixed declarations and code [-Werror=declaration-after-statement] 121 | Py_ssize_t sign = 1 - (op->long_value.lv_tag & _PyLong_SIGN_MASK); | ^~~~~~~~~~ So add -Wno-declaration-after-statement to the python binding CFLAGS. Reviewed-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/ZMpcTMvnQns81YWA@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/setup.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index 869738fc06c38..79d5e2955f85d 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py @@ -66,6 +66,9 @@ if cc_is_clang: else: cflags += ['-Wno-cast-function-type' ] +# The python headers have mixed code with declarations (decls after asserts, for instance) +cflags += [ "-Wno-declaration-after-statement" ] + src_perf = getenv('srctree') + '/tools/perf' build_lib = getenv('PYTHON_EXTBUILD_LIB') build_tmp = getenv('PYTHON_EXTBUILD_TMP') -- GitLab From c43888e739bbf184eb95018188215a5487cc0b15 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 2 Aug 2023 10:33:42 -0300 Subject: [PATCH 0790/3445] perf script python: Cope with declarations after statements found in Python.h With -Werror the build was failing on fedora rawhide: [perfbuilder@27cfe44d67ed perf-6.5.0-rc2]$ gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/13/lto-wrapper OFFLOAD_TARGET_NAMES=nvptx-none OFFLOAD_TARGET_DEFAULT=1 Target: x86_64-redhat-linux Configured with: ../configure --enable-bootstrap --enable-languages=c,c++,fortran,objc,obj-c++,ada,go,d,m2,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-gcc-major-version-only --enable-libstdcxx-backtrace --with-libstdcxx-zoneinfo=/usr/share/zoneinfo --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --with-isl=/builddir/build/BUILD/gcc-13.2.1-20230728/obj-x86_64-redhat-linux/isl-install --enable-offload-targets=nvptx-none --without-cuda-driver --enable-offload-defaulted --enable-gnu-indirect-function --enable-cet --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux --with-build-config=bootstrap-lto --enable-link-serialization=1 Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 13.2.1 20230728 (Red Hat 13.2.1-1) (GCC) [perfbuilder@27cfe44d67ed perf-6.5.0-rc2]$ In file included from /usr/include/python3.12/Python.h:44, from scripts/python/Perf-Trace-Util/Context.c:14: /usr/include/python3.12/object.h: In function 'Py_SIZE': /usr/include/python3.12/object.h:217:5: error: ISO C90 forbids mixed declarations and code [-Werror=declaration-after-statement] 217 | PyVarObject *var_ob = _PyVarObject_CAST(ob); | ^~~~~~~~~~~ In file included from /usr/include/python3.12/Python.h:53: /usr/include/python3.12/cpython/longintrepr.h: In function '_PyLong_CompactValue': /usr/include/python3.12/cpython/longintrepr.h:121:5: error: ISO C90 forbids mixed declarations and code [-Werror=declaration-after-statement] 121 | Py_ssize_t sign = 1 - (op->long_value.lv_tag & _PyLong_SIGN_MASK); | ^~~~~~~~~~ In file included from /usr/include/python3.12/Python.h:44, from util/scripting-engines/trace-event-python.c:22: /usr/include/python3.12/object.h: In function 'Py_SIZE': /usr/include/python3.12/object.h:217:5: error: ISO C90 forbids mixed declarations and code [-Werror=declaration-after-statement] 217 | PyVarObject *var_ob = _PyVarObject_CAST(ob); | ^~~~~~~~~~~ CC /tmp/build/perf/util/units.o CC /tmp/build/perf/util/time-utils.o In file included from /usr/include/python3.12/Python.h:53: /usr/include/python3.12/cpython/longintrepr.h: In function '_PyLong_CompactValue': /usr/include/python3.12/cpython/longintrepr.h:121:5: error: ISO C90 forbids mixed declarations and code [-Werror=declaration-after-statement] 121 | Py_ssize_t sign = 1 - (op->long_value.lv_tag & _PyLong_SIGN_MASK); | ^~~~~~~~~~ So add -Wno-declaration-after-statement to the python scripting CFLAGS. Reviewed-by: Ian Rogers Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/ZMpdKeO8gU%2FcWDqH@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/scripts/python/Perf-Trace-Util/Build | 3 ++- tools/perf/util/scripting-engines/Build | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Build b/tools/perf/scripts/python/Perf-Trace-Util/Build index 7d0e33ce6aba4..5b0b5ff7e14af 100644 --- a/tools/perf/scripts/python/Perf-Trace-Util/Build +++ b/tools/perf/scripts/python/Perf-Trace-Util/Build @@ -1,3 +1,4 @@ perf-y += Context.o -CFLAGS_Context.o += $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs +# -Wno-declaration-after-statement: The python headers have mixed code with declarations (decls after asserts, for instance) +CFLAGS_Context.o += $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs -Wno-declaration-after-statement diff --git a/tools/perf/util/scripting-engines/Build b/tools/perf/util/scripting-engines/Build index c220fec970324..586b94e90f4eb 100644 --- a/tools/perf/util/scripting-engines/Build +++ b/tools/perf/util/scripting-engines/Build @@ -5,4 +5,5 @@ perf-$(CONFIG_LIBPYTHON) += trace-event-python.o CFLAGS_trace-event-perl.o += $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-nested-externs -Wno-undef -Wno-switch-default -Wno-bad-function-cast -Wno-declaration-after-statement -Wno-switch-enum -CFLAGS_trace-event-python.o += $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-deprecated-declarations -Wno-switch-enum +# -Wno-declaration-after-statement: The python headers have mixed code with declarations (decls after asserts, for instance) +CFLAGS_trace-event-python.o += $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-deprecated-declarations -Wno-switch-enum -Wno-declaration-after-statement -- GitLab From 4e95ed4f4d5bc6838a10e6952999b41b1d07e56f Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Tue, 25 Jul 2023 17:03:46 +0200 Subject: [PATCH 0791/3445] perf build: Update feature check for clang and llvm Perf build auto-detects features and packages already installed for its build. This is done in directory tools/build/feature. This directory contains small sample programs. When they successfully compile the necessary prereqs in form of libraries and header files are present. Such a check is also done for llvm and clang. And the checks fail. Fix this and update to the latest C++ standard and use the new library provided by clang (which contains new packaging) s/ee this link for reference: https://fedoraproject.org/wiki/Changes/Stop-Shipping-Individual-Component-Libraries-In-clang-lib-Package Output before: # rm -f ./test-clang.bin; make test-clang.bin; ./test-clang.bin; \ ll test-clang.make.output g++ -MD -Wall -Werror -o test-clang.bin test-clang.cpp \ > test-clang.make.output 2>&1 -std=gnu++14 \ -I/usr/include \ -L/usr/lib64 \ -Wl,--start-group -lclangBasic -lclangDriver \ -lclangFrontend -lclangEdit -lclangLex \ -lclangAST -Wl,--end-group \ -lLLVM-16 \ \ > test-clang.make.output 2>&1 make: *** [Makefile:356: test-clang.bin] Error 1 -bash: ./test-clang.bin: No such file or directory -rw-r--r--. 1 root root 252041 Jul 12 09:56 test-clang.make.output # File test-clang.make.output contains many lines of unreferenced symbols. Output after: # rm -f ./test-clang.bin; make test-clang.bin; ./test-clang.bin; \ cat test-clang.make.output g++ -MD -Wall -Werror -o test-clang.bin test-clang.cpp \ > test-clang.make.output 2>&1 -std=gnu++17 \ -I/usr/include \ -L/usr/lib64 \ -Wl,--start-group -lclang-cpp -Wl,--end-group \ -lLLVM-16 \ \ > test-clang.make.output 2>&1 # Committer notes: Test it in the tools/build/feature directory, and have clang-devel and llvm-devel installed. Signed-off-by: Thomas Richter Tested-by: Arnaldo Carvalho de Melo Cc: Heiko Carstens Cc: Ian Rogers Cc: Jiri Olsa Cc: Sumanth Korikkar Cc: Sven Schnelle Cc: Vasily Gorbik Cc: Wang Nan Link: https://lore.kernel.org/r/20230725150347.3479291-1-tmricht@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/feature/Makefile | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index 2cd6dbbee0887..3184f387990a8 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile @@ -340,7 +340,7 @@ $(OUTPUT)test-jvmti-cmlr.bin: $(BUILD) $(OUTPUT)test-llvm.bin: - $(BUILDXX) -std=gnu++14 \ + $(BUILDXX) -std=gnu++17 \ -I$(shell $(LLVM_CONFIG) --includedir) \ -L$(shell $(LLVM_CONFIG) --libdir) \ $(shell $(LLVM_CONFIG) --libs Core BPF) \ @@ -348,17 +348,15 @@ $(OUTPUT)test-llvm.bin: > $(@:.bin=.make.output) 2>&1 $(OUTPUT)test-llvm-version.bin: - $(BUILDXX) -std=gnu++14 \ + $(BUILDXX) -std=gnu++17 \ -I$(shell $(LLVM_CONFIG) --includedir) \ > $(@:.bin=.make.output) 2>&1 $(OUTPUT)test-clang.bin: - $(BUILDXX) -std=gnu++14 \ + $(BUILDXX) -std=gnu++17 \ -I$(shell $(LLVM_CONFIG) --includedir) \ -L$(shell $(LLVM_CONFIG) --libdir) \ - -Wl,--start-group -lclangBasic -lclangDriver \ - -lclangFrontend -lclangEdit -lclangLex \ - -lclangAST -Wl,--end-group \ + -Wl,--start-group -lclang-cpp -Wl,--end-group \ $(shell $(LLVM_CONFIG) --libs Core option) \ $(shell $(LLVM_CONFIG) --system-libs) \ > $(@:.bin=.make.output) 2>&1 -- GitLab From 8fcaea9fd0dabc33f1a18f62aa3cf3d12286cd9f Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Tue, 25 Jul 2023 17:03:47 +0200 Subject: [PATCH 0792/3445] perf build: Support llvm and clang support compiled in Perf build suports llvm and clang support compiled in. Test case 56 builtin clang support provides a test case which is always skipped. Link perf with the latest llvm and clang libraries and enable this test case. Use 'make LIBCLANGLLVM=1' to include this support. V2: Add Library patch before -lclang-cpp Output before: # ./perf test 56 56: builtin clang support : 56.1: builtin clang compile C source to IR : Skip (not compiled in) 56.2: builtin clang compile C source to ELF object: Skip (not compiled in) Output after: # ./perf test 56 56: builtin clang support : 56.1: builtin clang compile C source to IR : Ok 56.2: builtin clang compile C source to ELF object : Ok # From Ian Rogers: Build tested with LLVM 14 and 15 using: BUILD_BPF_SKEL=1 LIBCLANGLLVM=1 LLVM_CONFIG=llvm-config-14 BUILD_BPF_SKEL=1 LIBCLANGLLVM=1 LLVM_CONFIG=llvm-config-15 Signed-off-by: Thomas Richter Tested-by: Arnaldo Carvalho de Melo Tested-by: Ian Rogers Cc: Heiko Carstens Cc: Jiri Olsa Cc: Sumanth Korikkar Cc: Sven Schnelle Cc: Thomas Richter Cc: Vasily Gorbik Cc: Wang Nan Link: https://lore.kernel.org/r/20230725150347.3479291-2-tmricht@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.config | 2 +- tools/perf/Makefile.perf | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index fe7afe6d8529f..1bf8dc53641fa 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -331,7 +331,7 @@ CORE_CFLAGS += -Wall CORE_CFLAGS += -Wextra CORE_CFLAGS += -std=gnu11 -CXXFLAGS += -std=gnu++14 -fno-exceptions -fno-rtti +CXXFLAGS += -std=gnu++17 -fno-exceptions -fno-rtti CXXFLAGS += -Wall CXXFLAGS += -Wextra CXXFLAGS += -fno-omit-frame-pointer diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index a44d16ec11ee5..0ed7ee0c1665a 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -426,10 +426,7 @@ EXTLIBS := $(call filter-out,$(EXCLUDE_EXTLIBS),$(EXTLIBS)) LIBS = -Wl,--whole-archive $(PERFLIBS) $(EXTRA_PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group ifeq ($(USE_CLANG), 1) - CLANGLIBS_LIST = AST Basic CodeGen Driver Frontend Lex Tooling Edit Sema Analysis Parse Serialization - CLANGLIBS_NOEXT_LIST = $(foreach l,$(CLANGLIBS_LIST),$(shell $(LLVM_CONFIG) --libdir)/libclang$(l)) - LIBCLANG = $(foreach l,$(CLANGLIBS_NOEXT_LIST),$(wildcard $(l).a $(l).so)) - LIBS += -Wl,--start-group $(LIBCLANG) -Wl,--end-group + LIBS += -L$(shell $(LLVM_CONFIG) --libdir) -lclang-cpp endif ifeq ($(USE_LLVM), 1) -- GitLab From 979e9c9fc9c2a761303585e07fe2699bdd88182f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 2 Aug 2023 18:22:14 -0300 Subject: [PATCH 0793/3445] perf annotate bpf: Don't enclose non-debug code with an assert() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In 616b14b47a86d880 ("perf build: Conditionally define NDEBUG") we started using NDEBUG=1 when DEBUG=1 isn't present, so code that is enclosed with assert() is not called. In dd317df072071903 ("perf build: Make binutil libraries opt in") we stopped linking against binutils-devel, for licensing reasons. Recently people asked me why annotation of BPF programs wasn't working, i.e. this: $ perf annotate bpf_prog_5280546344e3f45c_kfree_skb was returning: case SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF: scnprintf(buf, buflen, "Please link with binutils's libopcode to enable BPF annotation"); This was on a fedora rpm, so its new enough that I had to try to test by rebuilding using BUILD_NONDISTRO=1, only to get it segfaulting on me. This combination made this libopcode function not to be called: assert(bfd_check_format(bfdf, bfd_object)); Changing it to: if (!bfd_check_format(bfdf, bfd_object)) abort(); Made it work, looking at this "check" function made me realize it changes the 'bfdf' internal state, i.e. we better call it. So stop using assert() on it, just call it and abort if it fails. Probably it is better to propagate the error, etc, but it seems it is unlikely to fail from the usage done so far and we really need to stop using libopcodes, so do the quick fix above and move on. With it we have BPF annotation back working when built with BUILD_NONDISTRO=1: ⬢[acme@toolbox perf-tools-next]$ perf annotate --stdio2 bpf_prog_5280546344e3f45c_kfree_skb | head No kallsyms or vmlinux with build-id 939bc71a1a51cdc434e60af93c7e734f7d5c0e7e was found Samples: 12 of event 'cpu-clock:ppp', 4000 Hz, Event count (approx.): 3000000, [percent: local period] bpf_prog_5280546344e3f45c_kfree_skb() bpf_prog_5280546344e3f45c_kfree_skb Percent int kfree_skb(struct trace_event_raw_kfree_skb *args) { nop 33.33 xchg %ax,%ax push %rbp mov %rsp,%rbp sub $0x180,%rsp push %rbx push %r13 ⬢[acme@toolbox perf-tools-next]$ Fixes: 6987561c9e86eace ("perf annotate: Enable annotation of BPF programs") Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Cc: Mohamed Mahmoud Cc: Namhyung Kim Cc: Dave Tucker Cc: Derek Barbosa Cc: Song Liu Link: https://lore.kernel.org/lkml/ZMrMzoQBe0yqMek1@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index ba988a13dacb6..82956adf99632 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1846,8 +1846,11 @@ static int symbol__disassemble_bpf(struct symbol *sym, perf_exe(tpath, sizeof(tpath)); bfdf = bfd_openr(tpath, NULL); - assert(bfdf); - assert(bfd_check_format(bfdf, bfd_object)); + if (bfdf == NULL) + abort(); + + if (!bfd_check_format(bfdf, bfd_object)) + abort(); s = open_memstream(&buf, &buf_size); if (!s) { @@ -1895,7 +1898,8 @@ static int symbol__disassemble_bpf(struct symbol *sym, #else disassemble = disassembler(bfdf); #endif - assert(disassemble); + if (disassemble == NULL) + abort(); fflush(s); do { -- GitLab From e2cabf2a44791f01c21f8d5189b946926e34142e Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 31 Jul 2023 02:49:32 -0700 Subject: [PATCH 0794/3445] perf hists browser: Fix hierarchy mode header The commit ef9ff6017e3c4593 ("perf ui browser: Move the extra title lines from the hists browser") introduced ui_browser__gotorc_title() to help moving non-title lines easily. But it missed to update the title for the hierarchy mode so it won't print the header line on TUI at all. $ perf report --hierarchy Fixes: ef9ff6017e3c4593 ("perf ui browser: Move the extra title lines from the hists browser") Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Peter Zijlstra Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20230731094934.1616495-1-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index c7ad9e0030800..d8b88f10a48da 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -1779,7 +1779,7 @@ static void hists_browser__hierarchy_headers(struct hist_browser *browser) hists_browser__scnprintf_hierarchy_headers(browser, headers, sizeof(headers)); - ui_browser__gotorc(&browser->b, 0, 0); + ui_browser__gotorc_title(&browser->b, 0, 0); ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); } -- GitLab From f6b8436bede3e80226e8b2100279c4450c73806a Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 31 Jul 2023 02:49:33 -0700 Subject: [PATCH 0795/3445] perf hists browser: Fix the number of entries for 'e' key The 'e' key is to toggle expand/collapse the selected entry only. But the current code has a bug that it only increases the number of entries by 1 in the hierarchy mode so users cannot move under the current entry after the key stroke. This is due to a wrong assumption in the hist_entry__set_folding(). The commit b33f922651011eff ("perf hists browser: Put hist_entry folding logic into single function") factored out the code, but actually it should be handled separately. The hist_browser__set_folding() is to update fold state for each entry so it needs to traverse all (child) entries regardless of the current fold state. So it increases the number of entries by 1. But the hist_entry__set_folding() only cares the currently selected entry and its all children. So it should count all unfolded child entries. This code is implemented in hist_browser__toggle_fold() already so we can just call it. Fixes: b33f922651011eff ("perf hists browser: Put hist_entry folding logic into single function") Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Peter Zijlstra Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20230731094934.1616495-2-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 58 ++++++++++++++-------------------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index d8b88f10a48da..70db5a7179056 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -407,11 +407,6 @@ static bool hist_browser__selection_has_children(struct hist_browser *browser) return container_of(ms, struct callchain_list, ms)->has_children; } -static bool hist_browser__he_selection_unfolded(struct hist_browser *browser) -{ - return browser->he_selection ? browser->he_selection->unfolded : false; -} - static bool hist_browser__selection_unfolded(struct hist_browser *browser) { struct hist_entry *he = browser->he_selection; @@ -584,8 +579,8 @@ static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he, return n; } -static void __hist_entry__set_folding(struct hist_entry *he, - struct hist_browser *hb, bool unfold) +static void hist_entry__set_folding(struct hist_entry *he, + struct hist_browser *hb, bool unfold) { hist_entry__init_have_children(he); he->unfolded = unfold ? he->has_children : false; @@ -603,34 +598,12 @@ static void __hist_entry__set_folding(struct hist_entry *he, he->nr_rows = 0; } -static void hist_entry__set_folding(struct hist_entry *he, - struct hist_browser *browser, bool unfold) -{ - double percent; - - percent = hist_entry__get_percent_limit(he); - if (he->filtered || percent < browser->min_pcnt) - return; - - __hist_entry__set_folding(he, browser, unfold); - - if (!he->depth || unfold) - browser->nr_hierarchy_entries++; - if (he->leaf) - browser->nr_callchain_rows += he->nr_rows; - else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) { - browser->nr_hierarchy_entries++; - he->has_no_entry = true; - he->nr_rows = 1; - } else - he->has_no_entry = false; -} - static void __hist_browser__set_folding(struct hist_browser *browser, bool unfold) { struct rb_node *nd; struct hist_entry *he; + double percent; nd = rb_first_cached(&browser->hists->entries); while (nd) { @@ -640,6 +613,21 @@ __hist_browser__set_folding(struct hist_browser *browser, bool unfold) nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD); hist_entry__set_folding(he, browser, unfold); + + percent = hist_entry__get_percent_limit(he); + if (he->filtered || percent < browser->min_pcnt) + continue; + + if (!he->depth || unfold) + browser->nr_hierarchy_entries++; + if (he->leaf) + browser->nr_callchain_rows += he->nr_rows; + else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) { + browser->nr_hierarchy_entries++; + he->has_no_entry = true; + he->nr_rows = 1; + } else + he->has_no_entry = false; } } @@ -659,8 +647,10 @@ static void hist_browser__set_folding_selected(struct hist_browser *browser, boo if (!browser->he_selection) return; - hist_entry__set_folding(browser->he_selection, browser, unfold); - browser->b.nr_entries = hist_browser__nr_entries(browser); + if (unfold == browser->he_selection->unfolded) + return; + + hist_browser__toggle_fold(browser); } static void ui_browser__warn_lost_events(struct ui_browser *browser) @@ -732,8 +722,8 @@ static int hist_browser__handle_hotkey(struct hist_browser *browser, bool warn_l hist_browser__set_folding(browser, true); break; case 'e': - /* Expand the selected entry. */ - hist_browser__set_folding_selected(browser, !hist_browser__he_selection_unfolded(browser)); + /* Toggle expand/collapse the selected entry. */ + hist_browser__toggle_fold(browser); break; case 'H': browser->show_headers = !browser->show_headers; -- GitLab From b23c83ad2c638420ec0608a9de354507c41bec29 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 21 Jul 2023 13:18:41 -0700 Subject: [PATCH 0796/3445] x86/reboot: VMCLEAR active VMCSes before emergency reboot VMCLEAR active VMCSes before any emergency reboot, not just if the kernel may kexec into a new kernel after a crash. Per Intel's SDM, the VMX architecture doesn't require the CPU to flush the VMCS cache on INIT. If an emergency reboot doesn't RESET CPUs, cached VMCSes could theoretically be kept and only be written back to memory after the new kernel is booted, i.e. could effectively corrupt memory after reboot. Opportunistically remove the setting of the global pointer to NULL to make checkpatch happy. Cc: Andrew Cooper Link: https://lore.kernel.org/r/20230721201859.2307736-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kexec.h | 2 -- arch/x86/include/asm/reboot.h | 2 ++ arch/x86/kernel/crash.c | 31 ------------------------------- arch/x86/kernel/reboot.c | 22 ++++++++++++++++++++++ arch/x86/kvm/vmx/vmx.c | 10 +++------- 5 files changed, 27 insertions(+), 40 deletions(-) diff --git a/arch/x86/include/asm/kexec.h b/arch/x86/include/asm/kexec.h index 5b77bbc28f969..819046974b997 100644 --- a/arch/x86/include/asm/kexec.h +++ b/arch/x86/include/asm/kexec.h @@ -205,8 +205,6 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image); #endif #endif -typedef void crash_vmclear_fn(void); -extern crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss; extern void kdump_nmi_shootdown_cpus(void); #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/include/asm/reboot.h b/arch/x86/include/asm/reboot.h index 9177b4354c3f5..dc201724a6433 100644 --- a/arch/x86/include/asm/reboot.h +++ b/arch/x86/include/asm/reboot.h @@ -25,6 +25,8 @@ void __noreturn machine_real_restart(unsigned int type); #define MRR_BIOS 0 #define MRR_APM 1 +typedef void crash_vmclear_fn(void); +extern crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss; void cpu_emergency_disable_virtualization(void); typedef void (*nmi_shootdown_cb)(int, struct pt_regs*); diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c index cdd92ab43cda4..54cd959cb3160 100644 --- a/arch/x86/kernel/crash.c +++ b/arch/x86/kernel/crash.c @@ -48,38 +48,12 @@ struct crash_memmap_data { unsigned int type; }; -/* - * This is used to VMCLEAR all VMCSs loaded on the - * processor. And when loading kvm_intel module, the - * callback function pointer will be assigned. - * - * protected by rcu. - */ -crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss = NULL; -EXPORT_SYMBOL_GPL(crash_vmclear_loaded_vmcss); - -static inline void cpu_crash_vmclear_loaded_vmcss(void) -{ - crash_vmclear_fn *do_vmclear_operation = NULL; - - rcu_read_lock(); - do_vmclear_operation = rcu_dereference(crash_vmclear_loaded_vmcss); - if (do_vmclear_operation) - do_vmclear_operation(); - rcu_read_unlock(); -} - #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) static void kdump_nmi_callback(int cpu, struct pt_regs *regs) { crash_save_cpu(regs, cpu); - /* - * VMCLEAR VMCSs loaded on all cpus if needed. - */ - cpu_crash_vmclear_loaded_vmcss(); - /* * Disable Intel PT to stop its logging */ @@ -133,11 +107,6 @@ void native_machine_crash_shutdown(struct pt_regs *regs) crash_smp_send_stop(); - /* - * VMCLEAR VMCSs loaded on this cpu if needed. - */ - cpu_crash_vmclear_loaded_vmcss(); - cpu_emergency_disable_virtualization(); /* diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 3adbe97015c13..3fa4c6717a1db 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -787,6 +787,26 @@ void machine_crash_shutdown(struct pt_regs *regs) } #endif +/* + * This is used to VMCLEAR all VMCSs loaded on the + * processor. And when loading kvm_intel module, the + * callback function pointer will be assigned. + * + * protected by rcu. + */ +crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss; +EXPORT_SYMBOL_GPL(crash_vmclear_loaded_vmcss); + +static inline void cpu_crash_vmclear_loaded_vmcss(void) +{ + crash_vmclear_fn *do_vmclear_operation = NULL; + + rcu_read_lock(); + do_vmclear_operation = rcu_dereference(crash_vmclear_loaded_vmcss); + if (do_vmclear_operation) + do_vmclear_operation(); + rcu_read_unlock(); +} /* This is the CPU performing the emergency shutdown work. */ int crashing_cpu = -1; @@ -798,6 +818,8 @@ int crashing_cpu = -1; */ void cpu_emergency_disable_virtualization(void) { + cpu_crash_vmclear_loaded_vmcss(); + cpu_emergency_vmxoff(); cpu_emergency_svm_disable(); } diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index e6d1ce2d230cb..75351477f090c 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include @@ -725,7 +725,6 @@ static int vmx_set_guest_uret_msr(struct vcpu_vmx *vmx, return ret; } -#ifdef CONFIG_KEXEC_CORE static void crash_vmclear_local_loaded_vmcss(void) { int cpu = raw_smp_processor_id(); @@ -735,7 +734,6 @@ static void crash_vmclear_local_loaded_vmcss(void) loaded_vmcss_on_cpu_link) vmcs_clear(v->vmcs); } -#endif /* CONFIG_KEXEC_CORE */ static void __loaded_vmcs_clear(void *arg) { @@ -8573,10 +8571,9 @@ static void __vmx_exit(void) { allow_smaller_maxphyaddr = false; -#ifdef CONFIG_KEXEC_CORE RCU_INIT_POINTER(crash_vmclear_loaded_vmcss, NULL); synchronize_rcu(); -#endif + vmx_cleanup_l1d_flush(); } @@ -8623,10 +8620,9 @@ static int __init vmx_init(void) pi_init_cpu(cpu); } -#ifdef CONFIG_KEXEC_CORE rcu_assign_pointer(crash_vmclear_loaded_vmcss, crash_vmclear_local_loaded_vmcss); -#endif + vmx_check_vmcs12_offsets(); /* -- GitLab From 5e408396c60cd0f0b53a43713016b6d6af8d69e0 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 21 Jul 2023 13:18:42 -0700 Subject: [PATCH 0797/3445] x86/reboot: Harden virtualization hooks for emergency reboot Provide dedicated helpers to (un)register virt hooks used during an emergency crash/reboot, and WARN if there is an attempt to overwrite the registered callback, or an attempt to do an unpaired unregister. Opportunsitically use rcu_assign_pointer() instead of RCU_INIT_POINTER(), mainly so that the set/unset paths are more symmetrical, but also because any performance gains from using RCU_INIT_POINTER() are meaningless for this code. Reviewed-by: Kai Huang Link: https://lore.kernel.org/r/20230721201859.2307736-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/reboot.h | 5 +++-- arch/x86/kernel/reboot.c | 30 ++++++++++++++++++++++++------ arch/x86/kvm/vmx/vmx.c | 6 ++---- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/arch/x86/include/asm/reboot.h b/arch/x86/include/asm/reboot.h index dc201724a6433..74c6a624d1669 100644 --- a/arch/x86/include/asm/reboot.h +++ b/arch/x86/include/asm/reboot.h @@ -25,8 +25,9 @@ void __noreturn machine_real_restart(unsigned int type); #define MRR_BIOS 0 #define MRR_APM 1 -typedef void crash_vmclear_fn(void); -extern crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss; +typedef void (cpu_emergency_virt_cb)(void); +void cpu_emergency_register_virt_callback(cpu_emergency_virt_cb *callback); +void cpu_emergency_unregister_virt_callback(cpu_emergency_virt_cb *callback); void cpu_emergency_disable_virtualization(void); typedef void (*nmi_shootdown_cb)(int, struct pt_regs*); diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 3fa4c6717a1db..62ccedeb5e2b8 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -794,17 +794,35 @@ void machine_crash_shutdown(struct pt_regs *regs) * * protected by rcu. */ -crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss; -EXPORT_SYMBOL_GPL(crash_vmclear_loaded_vmcss); +static cpu_emergency_virt_cb __rcu *cpu_emergency_virt_callback; + +void cpu_emergency_register_virt_callback(cpu_emergency_virt_cb *callback) +{ + if (WARN_ON_ONCE(rcu_access_pointer(cpu_emergency_virt_callback))) + return; + + rcu_assign_pointer(cpu_emergency_virt_callback, callback); +} +EXPORT_SYMBOL_GPL(cpu_emergency_register_virt_callback); + +void cpu_emergency_unregister_virt_callback(cpu_emergency_virt_cb *callback) +{ + if (WARN_ON_ONCE(rcu_access_pointer(cpu_emergency_virt_callback) != callback)) + return; + + rcu_assign_pointer(cpu_emergency_virt_callback, NULL); + synchronize_rcu(); +} +EXPORT_SYMBOL_GPL(cpu_emergency_unregister_virt_callback); static inline void cpu_crash_vmclear_loaded_vmcss(void) { - crash_vmclear_fn *do_vmclear_operation = NULL; + cpu_emergency_virt_cb *callback; rcu_read_lock(); - do_vmclear_operation = rcu_dereference(crash_vmclear_loaded_vmcss); - if (do_vmclear_operation) - do_vmclear_operation(); + callback = rcu_dereference(cpu_emergency_virt_callback); + if (callback) + callback(); rcu_read_unlock(); } diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 75351477f090c..661ba09685b8a 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -8571,8 +8571,7 @@ static void __vmx_exit(void) { allow_smaller_maxphyaddr = false; - RCU_INIT_POINTER(crash_vmclear_loaded_vmcss, NULL); - synchronize_rcu(); + cpu_emergency_unregister_virt_callback(crash_vmclear_local_loaded_vmcss); vmx_cleanup_l1d_flush(); } @@ -8620,8 +8619,7 @@ static int __init vmx_init(void) pi_init_cpu(cpu); } - rcu_assign_pointer(crash_vmclear_loaded_vmcss, - crash_vmclear_local_loaded_vmcss); + cpu_emergency_register_virt_callback(crash_vmclear_local_loaded_vmcss); vmx_check_vmcs12_offsets(); -- GitLab From 119b5cb4ffd0166f3e98e9ee042f5046f7744f28 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 21 Jul 2023 13:18:43 -0700 Subject: [PATCH 0798/3445] x86/reboot: KVM: Handle VMXOFF in KVM's reboot callback Use KVM VMX's reboot/crash callback to do VMXOFF in an emergency instead of manually and blindly doing VMXOFF. There's no need to attempt VMXOFF if a hypervisor, i.e. KVM, isn't loaded/active, i.e. if the CPU can't possibly be post-VMXON. Reviewed-by: Kai Huang Link: https://lore.kernel.org/r/20230721201859.2307736-4-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/virtext.h | 10 ---------- arch/x86/kernel/reboot.c | 29 +++++++++-------------------- arch/x86/kvm/vmx/vmx.c | 8 +++++--- 3 files changed, 14 insertions(+), 33 deletions(-) diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h index 3b12e6b994123..5bc29fab15da7 100644 --- a/arch/x86/include/asm/virtext.h +++ b/arch/x86/include/asm/virtext.h @@ -70,16 +70,6 @@ static inline void __cpu_emergency_vmxoff(void) cpu_vmxoff(); } -/** Disable VMX if it is supported and enabled on the current CPU - */ -static inline void cpu_emergency_vmxoff(void) -{ - if (cpu_has_vmx()) - __cpu_emergency_vmxoff(); -} - - - /* * SVM functions: diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 62ccedeb5e2b8..d2d0f2672a64d 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -787,13 +787,7 @@ void machine_crash_shutdown(struct pt_regs *regs) } #endif -/* - * This is used to VMCLEAR all VMCSs loaded on the - * processor. And when loading kvm_intel module, the - * callback function pointer will be assigned. - * - * protected by rcu. - */ +/* RCU-protected callback to disable virtualization prior to reboot. */ static cpu_emergency_virt_cb __rcu *cpu_emergency_virt_callback; void cpu_emergency_register_virt_callback(cpu_emergency_virt_cb *callback) @@ -815,17 +809,6 @@ void cpu_emergency_unregister_virt_callback(cpu_emergency_virt_cb *callback) } EXPORT_SYMBOL_GPL(cpu_emergency_unregister_virt_callback); -static inline void cpu_crash_vmclear_loaded_vmcss(void) -{ - cpu_emergency_virt_cb *callback; - - rcu_read_lock(); - callback = rcu_dereference(cpu_emergency_virt_callback); - if (callback) - callback(); - rcu_read_unlock(); -} - /* This is the CPU performing the emergency shutdown work. */ int crashing_cpu = -1; @@ -836,9 +819,15 @@ int crashing_cpu = -1; */ void cpu_emergency_disable_virtualization(void) { - cpu_crash_vmclear_loaded_vmcss(); + cpu_emergency_virt_cb *callback; + + rcu_read_lock(); + callback = rcu_dereference(cpu_emergency_virt_callback); + if (callback) + callback(); + rcu_read_unlock(); - cpu_emergency_vmxoff(); + /* KVM_AMD doesn't yet utilize the common callback. */ cpu_emergency_svm_disable(); } diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 661ba09685b8a..df991f15baf49 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -725,7 +725,7 @@ static int vmx_set_guest_uret_msr(struct vcpu_vmx *vmx, return ret; } -static void crash_vmclear_local_loaded_vmcss(void) +static void vmx_emergency_disable(void) { int cpu = raw_smp_processor_id(); struct loaded_vmcs *v; @@ -733,6 +733,8 @@ static void crash_vmclear_local_loaded_vmcss(void) list_for_each_entry(v, &per_cpu(loaded_vmcss_on_cpu, cpu), loaded_vmcss_on_cpu_link) vmcs_clear(v->vmcs); + + __cpu_emergency_vmxoff(); } static void __loaded_vmcs_clear(void *arg) @@ -8571,7 +8573,7 @@ static void __vmx_exit(void) { allow_smaller_maxphyaddr = false; - cpu_emergency_unregister_virt_callback(crash_vmclear_local_loaded_vmcss); + cpu_emergency_unregister_virt_callback(vmx_emergency_disable); vmx_cleanup_l1d_flush(); } @@ -8619,7 +8621,7 @@ static int __init vmx_init(void) pi_init_cpu(cpu); } - cpu_emergency_register_virt_callback(crash_vmclear_local_loaded_vmcss); + cpu_emergency_register_virt_callback(vmx_emergency_disable); vmx_check_vmcs12_offsets(); -- GitLab From baeb4de7ad12b700a91f2a7be8e1c0389a5c8fd4 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 21 Jul 2023 13:18:44 -0700 Subject: [PATCH 0799/3445] x86/reboot: KVM: Disable SVM during reboot via virt/KVM reboot callback Use the virt callback to disable SVM (and set GIF=1) during an emergency instead of blindly attempting to disable SVM. Like the VMX case, if a hypervisor, i.e. KVM, isn't loaded/active, SVM can't be in use. Acked-by: Kai Huang Link: https://lore.kernel.org/r/20230721201859.2307736-5-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/virtext.h | 8 -------- arch/x86/kernel/reboot.c | 3 --- arch/x86/kvm/svm/svm.c | 19 +++++++++++++++++-- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h index 5bc29fab15da7..aaed66249ccf3 100644 --- a/arch/x86/include/asm/virtext.h +++ b/arch/x86/include/asm/virtext.h @@ -133,12 +133,4 @@ fault: } } -/** Makes sure SVM is disabled, if it is supported on the CPU - */ -static inline void cpu_emergency_svm_disable(void) -{ - if (cpu_has_svm(NULL)) - cpu_svm_disable(); -} - #endif /* _ASM_X86_VIRTEX_H */ diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index d2d0f2672a64d..48ad2d1ff83d5 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -826,9 +826,6 @@ void cpu_emergency_disable_virtualization(void) if (callback) callback(); rcu_read_unlock(); - - /* KVM_AMD doesn't yet utilize the common callback. */ - cpu_emergency_svm_disable(); } #if defined(CONFIG_SMP) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index d381ad4245542..1ae9c2c7eacb3 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -563,6 +564,11 @@ out: preempt_enable(); } +static void svm_emergency_disable(void) +{ + cpu_svm_disable(); +} + static void svm_hardware_disable(void) { /* Make sure we clean up behind us */ @@ -5209,6 +5215,13 @@ static struct kvm_x86_init_ops svm_init_ops __initdata = { .pmu_ops = &amd_pmu_ops, }; +static void __svm_exit(void) +{ + kvm_x86_vendor_exit(); + + cpu_emergency_unregister_virt_callback(svm_emergency_disable); +} + static int __init svm_init(void) { int r; @@ -5222,6 +5235,8 @@ static int __init svm_init(void) if (r) return r; + cpu_emergency_register_virt_callback(svm_emergency_disable); + /* * Common KVM initialization _must_ come last, after this, /dev/kvm is * exposed to userspace! @@ -5234,14 +5249,14 @@ static int __init svm_init(void) return 0; err_kvm_init: - kvm_x86_vendor_exit(); + __svm_exit(); return r; } static void __exit svm_exit(void) { kvm_exit(); - kvm_x86_vendor_exit(); + __svm_exit(); } module_init(svm_init) -- GitLab From ad93c1a7c0102c93e92bf0c06412a1f588e015ab Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 21 Jul 2023 13:18:45 -0700 Subject: [PATCH 0800/3445] x86/reboot: Assert that IRQs are disabled when turning off virtualization Assert that IRQs are disabled when turning off virtualization in an emergency. KVM enables hardware via on_each_cpu(), i.e. could re-enable hardware if a pending IPI were delivered after disabling virtualization. Remove a misleading comment from emergency_reboot_disable_virtualization() about "just" needing to guarantee the CPU is stable (see above). Reviewed-by: Kai Huang Link: https://lore.kernel.org/r/20230721201859.2307736-6-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kernel/reboot.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 48ad2d1ff83d5..4cad7183b89e9 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -532,7 +532,6 @@ static inline void nmi_shootdown_cpus_on_restart(void); static void emergency_reboot_disable_virtualization(void) { - /* Just make sure we won't change CPUs while doing this */ local_irq_disable(); /* @@ -821,6 +820,13 @@ void cpu_emergency_disable_virtualization(void) { cpu_emergency_virt_cb *callback; + /* + * IRQs must be disabled as KVM enables virtualization in hardware via + * function call IPIs, i.e. IRQs need to be disabled to guarantee + * virtualization stays disabled. + */ + lockdep_assert_irqs_disabled(); + rcu_read_lock(); callback = rcu_dereference(cpu_emergency_virt_callback); if (callback) -- GitLab From edc8deb087d884bac2f7013f0c23af73042b23a7 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 21 Jul 2023 13:18:46 -0700 Subject: [PATCH 0801/3445] x86/reboot: Hoist "disable virt" helpers above "emergency reboot" path Move the various "disable virtualization" helpers above the emergency reboot path so that emergency_reboot_disable_virtualization() can be stubbed out in a future patch if neither KVM_INTEL nor KVM_AMD is enabled, i.e. if there is no in-tree user of CPU virtualization. No functional change intended. Reviewed-by: Kai Huang Link: https://lore.kernel.org/r/20230721201859.2307736-7-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kernel/reboot.c | 90 ++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 4cad7183b89e9..85cb2dfcb67bf 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -530,6 +530,51 @@ static inline void kb_wait(void) static inline void nmi_shootdown_cpus_on_restart(void); +/* RCU-protected callback to disable virtualization prior to reboot. */ +static cpu_emergency_virt_cb __rcu *cpu_emergency_virt_callback; + +void cpu_emergency_register_virt_callback(cpu_emergency_virt_cb *callback) +{ + if (WARN_ON_ONCE(rcu_access_pointer(cpu_emergency_virt_callback))) + return; + + rcu_assign_pointer(cpu_emergency_virt_callback, callback); +} +EXPORT_SYMBOL_GPL(cpu_emergency_register_virt_callback); + +void cpu_emergency_unregister_virt_callback(cpu_emergency_virt_cb *callback) +{ + if (WARN_ON_ONCE(rcu_access_pointer(cpu_emergency_virt_callback) != callback)) + return; + + rcu_assign_pointer(cpu_emergency_virt_callback, NULL); + synchronize_rcu(); +} +EXPORT_SYMBOL_GPL(cpu_emergency_unregister_virt_callback); + +/* + * Disable virtualization, i.e. VMX or SVM, to ensure INIT is recognized during + * reboot. VMX blocks INIT if the CPU is post-VMXON, and SVM blocks INIT if + * GIF=0, i.e. if the crash occurred between CLGI and STGI. + */ +void cpu_emergency_disable_virtualization(void) +{ + cpu_emergency_virt_cb *callback; + + /* + * IRQs must be disabled as KVM enables virtualization in hardware via + * function call IPIs, i.e. IRQs need to be disabled to guarantee + * virtualization stays disabled. + */ + lockdep_assert_irqs_disabled(); + + rcu_read_lock(); + callback = rcu_dereference(cpu_emergency_virt_callback); + if (callback) + callback(); + rcu_read_unlock(); +} + static void emergency_reboot_disable_virtualization(void) { local_irq_disable(); @@ -786,54 +831,9 @@ void machine_crash_shutdown(struct pt_regs *regs) } #endif -/* RCU-protected callback to disable virtualization prior to reboot. */ -static cpu_emergency_virt_cb __rcu *cpu_emergency_virt_callback; - -void cpu_emergency_register_virt_callback(cpu_emergency_virt_cb *callback) -{ - if (WARN_ON_ONCE(rcu_access_pointer(cpu_emergency_virt_callback))) - return; - - rcu_assign_pointer(cpu_emergency_virt_callback, callback); -} -EXPORT_SYMBOL_GPL(cpu_emergency_register_virt_callback); - -void cpu_emergency_unregister_virt_callback(cpu_emergency_virt_cb *callback) -{ - if (WARN_ON_ONCE(rcu_access_pointer(cpu_emergency_virt_callback) != callback)) - return; - - rcu_assign_pointer(cpu_emergency_virt_callback, NULL); - synchronize_rcu(); -} -EXPORT_SYMBOL_GPL(cpu_emergency_unregister_virt_callback); - /* This is the CPU performing the emergency shutdown work. */ int crashing_cpu = -1; -/* - * Disable virtualization, i.e. VMX or SVM, to ensure INIT is recognized during - * reboot. VMX blocks INIT if the CPU is post-VMXON, and SVM blocks INIT if - * GIF=0, i.e. if the crash occurred between CLGI and STGI. - */ -void cpu_emergency_disable_virtualization(void) -{ - cpu_emergency_virt_cb *callback; - - /* - * IRQs must be disabled as KVM enables virtualization in hardware via - * function call IPIs, i.e. IRQs need to be disabled to guarantee - * virtualization stays disabled. - */ - lockdep_assert_irqs_disabled(); - - rcu_read_lock(); - callback = rcu_dereference(cpu_emergency_virt_callback); - if (callback) - callback(); - rcu_read_unlock(); -} - #if defined(CONFIG_SMP) static nmi_shootdown_cb shootdown_callback; -- GitLab From 59765db5fc82726b32876b794667e2c6936a98ab Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 21 Jul 2023 13:18:47 -0700 Subject: [PATCH 0802/3445] x86/reboot: Disable virtualization during reboot iff callback is registered Attempt to disable virtualization during an emergency reboot if and only if there is a registered virt callback, i.e. iff a hypervisor (KVM) is active. If there's no active hypervisor, then the CPU can't be operating with VMX or SVM enabled (barring an egregious bug). Checking for a valid callback instead of simply for SVM or VMX support can also eliminates spurious NMIs by avoiding the unecessary call to nmi_shootdown_cpus_on_restart(). Note, IRQs are disabled, which prevents KVM from coming along and enabling virtualization after the fact. Reviewed-by: Kai Huang Link: https://lore.kernel.org/r/20230721201859.2307736-8-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kernel/reboot.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 85cb2dfcb67bf..98e5db3fd7f42 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -589,7 +588,7 @@ static void emergency_reboot_disable_virtualization(void) * Do the NMI shootdown even if virtualization is off on _this_ CPU, as * other CPUs may have virtualization enabled. */ - if (cpu_has_vmx() || cpu_has_svm(NULL)) { + if (rcu_access_pointer(cpu_emergency_virt_callback)) { /* Safely force _this_ CPU out of VMX/SVM operation. */ cpu_emergency_disable_virtualization(); -- GitLab From 261cd5ed934e6923187cf1c9eaa6cb63f2b81212 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 21 Jul 2023 13:18:48 -0700 Subject: [PATCH 0803/3445] x86/reboot: Expose VMCS crash hooks if and only if KVM_{INTEL,AMD} is enabled Expose the crash/reboot hooks used by KVM to disable virtualization in hardware and unblock INIT only if there's a potential in-tree user, i.e. either KVM_INTEL or KVM_AMD is enabled. Reviewed-by: Kai Huang Link: https://lore.kernel.org/r/20230721201859.2307736-9-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/reboot.h | 4 ++++ arch/x86/kernel/reboot.c | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/reboot.h b/arch/x86/include/asm/reboot.h index 74c6a624d1669..6536873f8fc0a 100644 --- a/arch/x86/include/asm/reboot.h +++ b/arch/x86/include/asm/reboot.h @@ -25,10 +25,14 @@ void __noreturn machine_real_restart(unsigned int type); #define MRR_BIOS 0 #define MRR_APM 1 +#if IS_ENABLED(CONFIG_KVM_INTEL) || IS_ENABLED(CONFIG_KVM_AMD) typedef void (cpu_emergency_virt_cb)(void); void cpu_emergency_register_virt_callback(cpu_emergency_virt_cb *callback); void cpu_emergency_unregister_virt_callback(cpu_emergency_virt_cb *callback); void cpu_emergency_disable_virtualization(void); +#else +static inline void cpu_emergency_disable_virtualization(void) {} +#endif /* CONFIG_KVM_INTEL || CONFIG_KVM_AMD */ typedef void (*nmi_shootdown_cb)(int, struct pt_regs*); void nmi_shootdown_cpus(nmi_shootdown_cb callback); diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 98e5db3fd7f42..830425e6d38e2 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -529,6 +529,7 @@ static inline void kb_wait(void) static inline void nmi_shootdown_cpus_on_restart(void); +#if IS_ENABLED(CONFIG_KVM_INTEL) || IS_ENABLED(CONFIG_KVM_AMD) /* RCU-protected callback to disable virtualization prior to reboot. */ static cpu_emergency_virt_cb __rcu *cpu_emergency_virt_callback; @@ -596,7 +597,9 @@ static void emergency_reboot_disable_virtualization(void) nmi_shootdown_cpus_on_restart(); } } - +#else +static void emergency_reboot_disable_virtualization(void) { } +#endif /* CONFIG_KVM_INTEL || CONFIG_KVM_AMD */ void __attribute__((weak)) mach_reboot_fixups(void) { -- GitLab From b6a6af0d19cea17a3c1e34f81f0d521775f94ab5 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 21 Jul 2023 13:18:49 -0700 Subject: [PATCH 0804/3445] x86/virt: KVM: Open code cpu_has_vmx() in KVM VMX Fold the raw CPUID check for VMX into kvm_is_vmx_supported(), its sole user. Keep the check even though KVM also checks X86_FEATURE_VMX, as the intent is to provide a unique error message if VMX is unsupported by hardware, whereas X86_FEATURE_VMX may be clear due to firmware and/or kernel actions. No functional change intended. Reviewed-by: Kai Huang Link: https://lore.kernel.org/r/20230721201859.2307736-10-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/virtext.h | 10 ---------- arch/x86/kvm/vmx/vmx.c | 2 +- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h index aaed66249ccf3..b1171a5ad4525 100644 --- a/arch/x86/include/asm/virtext.h +++ b/arch/x86/include/asm/virtext.h @@ -22,14 +22,6 @@ /* * VMX functions: */ - -static inline int cpu_has_vmx(void) -{ - unsigned long ecx = cpuid_ecx(1); - return test_bit(5, &ecx); /* CPUID.1:ECX.VMX[bit 5] -> VT */ -} - - /** * cpu_vmxoff() - Disable VMX on the current CPU * @@ -61,8 +53,6 @@ static inline int cpu_vmx_enabled(void) } /** Disable VMX if it is enabled on the current CPU - * - * You shouldn't call this if cpu_has_vmx() returns 0. */ static inline void __cpu_emergency_vmxoff(void) { diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index df991f15baf49..4b9d688261726 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -2699,7 +2699,7 @@ static bool kvm_is_vmx_supported(void) { int cpu = raw_smp_processor_id(); - if (!cpu_has_vmx()) { + if (!(cpuid_ecx(1) & feature_bit(VMX))) { pr_err("VMX not supported by CPU %d\n", cpu); return false; } -- GitLab From 22e420e127399f2e75c8efddff763e92247f3da7 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 21 Jul 2023 13:18:50 -0700 Subject: [PATCH 0805/3445] x86/virt: KVM: Move VMXOFF helpers into KVM VMX Now that VMX is disabled in emergencies via the virt callbacks, move the VMXOFF helpers into KVM, the only remaining user. No functional change intended. Reviewed-by: Kai Huang Link: https://lore.kernel.org/r/20230721201859.2307736-11-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/virtext.h | 42 ---------------------------------- arch/x86/kvm/vmx/vmx.c | 29 ++++++++++++++++++++--- 2 files changed, 26 insertions(+), 45 deletions(-) diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h index b1171a5ad4525..a27801f2bc71c 100644 --- a/arch/x86/include/asm/virtext.h +++ b/arch/x86/include/asm/virtext.h @@ -19,48 +19,6 @@ #include #include -/* - * VMX functions: - */ -/** - * cpu_vmxoff() - Disable VMX on the current CPU - * - * Disable VMX and clear CR4.VMXE (even if VMXOFF faults) - * - * Note, VMXOFF causes a #UD if the CPU is !post-VMXON, but it's impossible to - * atomically track post-VMXON state, e.g. this may be called in NMI context. - * Eat all faults as all other faults on VMXOFF faults are mode related, i.e. - * faults are guaranteed to be due to the !post-VMXON check unless the CPU is - * magically in RM, VM86, compat mode, or at CPL>0. - */ -static inline int cpu_vmxoff(void) -{ - asm_volatile_goto("1: vmxoff\n\t" - _ASM_EXTABLE(1b, %l[fault]) - ::: "cc", "memory" : fault); - - cr4_clear_bits(X86_CR4_VMXE); - return 0; - -fault: - cr4_clear_bits(X86_CR4_VMXE); - return -EIO; -} - -static inline int cpu_vmx_enabled(void) -{ - return __read_cr4() & X86_CR4_VMXE; -} - -/** Disable VMX if it is enabled on the current CPU - */ -static inline void __cpu_emergency_vmxoff(void) -{ - if (cpu_vmx_enabled()) - cpu_vmxoff(); -} - - /* * SVM functions: */ diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 4b9d688261726..64377fe3a9904 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include "capabilities.h" @@ -725,6 +724,29 @@ static int vmx_set_guest_uret_msr(struct vcpu_vmx *vmx, return ret; } +/* + * Disable VMX and clear CR4.VMXE (even if VMXOFF faults) + * + * Note, VMXOFF causes a #UD if the CPU is !post-VMXON, but it's impossible to + * atomically track post-VMXON state, e.g. this may be called in NMI context. + * Eat all faults as all other faults on VMXOFF faults are mode related, i.e. + * faults are guaranteed to be due to the !post-VMXON check unless the CPU is + * magically in RM, VM86, compat mode, or at CPL>0. + */ +static int kvm_cpu_vmxoff(void) +{ + asm_volatile_goto("1: vmxoff\n\t" + _ASM_EXTABLE(1b, %l[fault]) + ::: "cc", "memory" : fault); + + cr4_clear_bits(X86_CR4_VMXE); + return 0; + +fault: + cr4_clear_bits(X86_CR4_VMXE); + return -EIO; +} + static void vmx_emergency_disable(void) { int cpu = raw_smp_processor_id(); @@ -734,7 +756,8 @@ static void vmx_emergency_disable(void) loaded_vmcss_on_cpu_link) vmcs_clear(v->vmcs); - __cpu_emergency_vmxoff(); + if (__read_cr4() & X86_CR4_VMXE) + kvm_cpu_vmxoff(); } static void __loaded_vmcs_clear(void *arg) @@ -2799,7 +2822,7 @@ static void vmx_hardware_disable(void) { vmclear_local_loaded_vmcss(); - if (cpu_vmxoff()) + if (kvm_cpu_vmxoff()) kvm_spurious_fault(); hv_reset_evmcs(); -- GitLab From 554856b69e3d1faae6f056f75ed6262b5eb01546 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 21 Jul 2023 13:18:51 -0700 Subject: [PATCH 0806/3445] KVM: SVM: Make KVM_AMD depend on CPU_SUP_AMD or CPU_SUP_HYGON Make building KVM SVM support depend on support for AMD or Hygon. KVM already effectively restricts SVM support to AMD and Hygon by virtue of the vendor string checks in cpu_has_svm(), and KVM VMX supports depends on one of its three known vendors (Intel, Centaur, or Zhaoxin). Add the CPU_SUP_HYGON clause even though CPU_SUP_HYGON selects CPU_SUP_AMD to document that KVM SVM support isn't just for AMD CPUs, and to prevent breakage should Hygon support ever become a standalone thing. Link: https://lore.kernel.org/r/20230721201859.2307736-12-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index 89ca7f4c14643..66dbd1f4d57df 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -101,7 +101,7 @@ config X86_SGX_KVM config KVM_AMD tristate "KVM for AMD processors support" - depends on KVM + depends on KVM && (CPU_SUP_AMD || CPU_SUP_HYGON) help Provides support for KVM on AMD processors equipped with the AMD-V (SVM) extensions. -- GitLab From 5df8ecfe3632d5879d1f154f7aa8de441b5d1c89 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 21 Jul 2023 13:18:52 -0700 Subject: [PATCH 0807/3445] x86/virt: Drop unnecessary check on extended CPUID level in cpu_has_svm() Drop the explicit check on the extended CPUID level in cpu_has_svm(), the kernel's cached CPUID info will leave the entire SVM leaf unset if said leaf is not supported by hardware. Prior to using cached information, the check was needed to avoid false positives due to Intel's rather crazy CPUID behavior of returning the values of the maximum supported leaf if the specified leaf is unsupported. Fixes: 682a8108872f ("x86/kvm/svm: Simplify cpu_has_svm()") Link: https://lore.kernel.org/r/20230721201859.2307736-13-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/virtext.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h index a27801f2bc71c..be50c414efe44 100644 --- a/arch/x86/include/asm/virtext.h +++ b/arch/x86/include/asm/virtext.h @@ -39,12 +39,6 @@ static inline int cpu_has_svm(const char **msg) return 0; } - if (boot_cpu_data.extended_cpuid_level < SVM_CPUID_FUNC) { - if (msg) - *msg = "can't execute cpuid_8000000a"; - return 0; - } - if (!boot_cpu_has(X86_FEATURE_SVM)) { if (msg) *msg = "svm not available"; -- GitLab From 85fd29dd5fe459b732e46c7a9782fc403c5604ed Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 21 Jul 2023 13:18:53 -0700 Subject: [PATCH 0808/3445] x86/virt: KVM: Open code cpu_has_svm() into kvm_is_svm_supported() Fold the guts of cpu_has_svm() into kvm_is_svm_supported(), its sole remaining user. No functional change intended. Reviewed-by: Kai Huang Link: https://lore.kernel.org/r/20230721201859.2307736-14-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/virtext.h | 28 ---------------------------- arch/x86/kvm/svm/svm.c | 11 ++++++++--- 2 files changed, 8 insertions(+), 31 deletions(-) diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h index be50c414efe44..632575e257d82 100644 --- a/arch/x86/include/asm/virtext.h +++ b/arch/x86/include/asm/virtext.h @@ -22,35 +22,7 @@ /* * SVM functions: */ - -/** Check if the CPU has SVM support - * - * You can use the 'msg' arg to get a message describing the problem, - * if the function returns zero. Simply pass NULL if you are not interested - * on the messages; gcc should take care of not generating code for - * the messages on this case. - */ -static inline int cpu_has_svm(const char **msg) -{ - if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD && - boot_cpu_data.x86_vendor != X86_VENDOR_HYGON) { - if (msg) - *msg = "not amd or hygon"; - return 0; - } - - if (!boot_cpu_has(X86_FEATURE_SVM)) { - if (msg) - *msg = "svm not available"; - return 0; - } - return 1; -} - - /** Disable SVM on the current CPU - * - * You should call this only if cpu_has_svm() returned true. */ static inline void cpu_svm_disable(void) { diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 1ae9c2c7eacb3..ff6c769aafb2f 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -521,11 +521,16 @@ static void svm_init_osvw(struct kvm_vcpu *vcpu) static bool kvm_is_svm_supported(void) { int cpu = raw_smp_processor_id(); - const char *msg; u64 vm_cr; - if (!cpu_has_svm(&msg)) { - pr_err("SVM not supported by CPU %d, %s\n", cpu, msg); + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD && + boot_cpu_data.x86_vendor != X86_VENDOR_HYGON) { + pr_err("CPU %d isn't AMD or Hygon\n", cpu); + return false; + } + + if (!boot_cpu_has(X86_FEATURE_SVM)) { + pr_err("SVM not supported by CPU %d\n", cpu); return false; } -- GitLab From c4db4f20f3bf619bacd3d705bf427016453eedb1 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 21 Jul 2023 13:18:54 -0700 Subject: [PATCH 0809/3445] KVM: SVM: Check that the current CPU supports SVM in kvm_is_svm_supported() Check "this" CPU instead of the boot CPU when querying SVM support so that the per-CPU checks done during hardware enabling actually function as intended, i.e. will detect issues where SVM isn't support on all CPUs. Disable migration for the use from svm_init() mostly so that the standard accessors for the per-CPU data can be used without getting yelled at by CONFIG_DEBUG_PREEMPT=y sanity checks. Preventing the "disabled by BIOS" error message from reporting the wrong CPU is largely a bonus, as ensuring a stable CPU during module load is a non-goal for KVM. Link: https://lore.kernel.org/all/ZAdxNgv0M6P63odE@google.com Cc: Kai Huang Cc: Chao Gao Reviewed-by: Kai Huang Link: https://lore.kernel.org/r/20230721201859.2307736-15-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/svm.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index ff6c769aafb2f..9e449167e71bb 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -518,18 +518,20 @@ static void svm_init_osvw(struct kvm_vcpu *vcpu) vcpu->arch.osvw.status |= 1; } -static bool kvm_is_svm_supported(void) +static bool __kvm_is_svm_supported(void) { - int cpu = raw_smp_processor_id(); + int cpu = smp_processor_id(); + struct cpuinfo_x86 *c = &cpu_data(cpu); + u64 vm_cr; - if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD && - boot_cpu_data.x86_vendor != X86_VENDOR_HYGON) { + if (c->x86_vendor != X86_VENDOR_AMD && + c->x86_vendor != X86_VENDOR_HYGON) { pr_err("CPU %d isn't AMD or Hygon\n", cpu); return false; } - if (!boot_cpu_has(X86_FEATURE_SVM)) { + if (!cpu_has(c, X86_FEATURE_SVM)) { pr_err("SVM not supported by CPU %d\n", cpu); return false; } @@ -548,9 +550,20 @@ static bool kvm_is_svm_supported(void) return true; } +static bool kvm_is_svm_supported(void) +{ + bool supported; + + migrate_disable(); + supported = __kvm_is_svm_supported(); + migrate_enable(); + + return supported; +} + static int svm_check_processor_compat(void) { - if (!kvm_is_svm_supported()) + if (!__kvm_is_svm_supported()) return -EIO; return 0; -- GitLab From f9a8866040fcf8672f20c67e07e67ba5a00caba4 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 21 Jul 2023 13:18:55 -0700 Subject: [PATCH 0810/3445] KVM: VMX: Ensure CPU is stable when probing basic VMX support Disable migration when probing VMX support during module load to ensure the CPU is stable, mostly to match similar SVM logic, where allowing migration effective requires deliberately writing buggy code. As a bonus, KVM won't report the wrong CPU to userspace if VMX is unsupported, but in practice that is a very, very minor bonus as the only way that reporting the wrong CPU would actually matter is if hardware is broken or if the system is misconfigured, i.e. if KVM gets migrated from a CPU that _does_ support VMX to a CPU that does _not_ support VMX. Reviewed-by: Kai Huang Link: https://lore.kernel.org/r/20230721201859.2307736-16-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 64377fe3a9904..ff0eced7d2abe 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -2718,9 +2718,9 @@ static int setup_vmcs_config(struct vmcs_config *vmcs_conf, return 0; } -static bool kvm_is_vmx_supported(void) +static bool __kvm_is_vmx_supported(void) { - int cpu = raw_smp_processor_id(); + int cpu = smp_processor_id(); if (!(cpuid_ecx(1) & feature_bit(VMX))) { pr_err("VMX not supported by CPU %d\n", cpu); @@ -2736,13 +2736,24 @@ static bool kvm_is_vmx_supported(void) return true; } +static bool kvm_is_vmx_supported(void) +{ + bool supported; + + migrate_disable(); + supported = __kvm_is_vmx_supported(); + migrate_enable(); + + return supported; +} + static int vmx_check_processor_compat(void) { int cpu = raw_smp_processor_id(); struct vmcs_config vmcs_conf; struct vmx_capability vmx_cap; - if (!kvm_is_vmx_supported()) + if (!__kvm_is_vmx_supported()) return -EIO; if (setup_vmcs_config(&vmcs_conf, &vmx_cap) < 0) { -- GitLab From 76ab8161083bfd0ae4de9b93e68d639da6e1c726 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 21 Jul 2023 13:18:56 -0700 Subject: [PATCH 0811/3445] x86/virt: KVM: Move "disable SVM" helper into KVM SVM Move cpu_svm_disable() into KVM proper now that all hardware virtualization management is routed through KVM. Remove the now-empty virtext.h. No functional change intended. Reviewed-by: Kai Huang Link: https://lore.kernel.org/r/20230721201859.2307736-17-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/virtext.h | 50 ---------------------------------- arch/x86/kvm/svm/svm.c | 29 +++++++++++++++++--- 2 files changed, 25 insertions(+), 54 deletions(-) delete mode 100644 arch/x86/include/asm/virtext.h diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h deleted file mode 100644 index 632575e257d82..0000000000000 --- a/arch/x86/include/asm/virtext.h +++ /dev/null @@ -1,50 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* CPU virtualization extensions handling - * - * This should carry the code for handling CPU virtualization extensions - * that needs to live in the kernel core. - * - * Author: Eduardo Habkost - * - * Copyright (C) 2008, Red Hat Inc. - * - * Contains code from KVM, Copyright (C) 2006 Qumranet, Inc. - */ -#ifndef _ASM_X86_VIRTEX_H -#define _ASM_X86_VIRTEX_H - -#include - -#include -#include -#include - -/* - * SVM functions: - */ -/** Disable SVM on the current CPU - */ -static inline void cpu_svm_disable(void) -{ - uint64_t efer; - - wrmsrl(MSR_VM_HSAVE_PA, 0); - rdmsrl(MSR_EFER, efer); - if (efer & EFER_SVME) { - /* - * Force GIF=1 prior to disabling SVM to ensure INIT and NMI - * aren't blocked, e.g. if a fatal error occurred between CLGI - * and STGI. Note, STGI may #UD if SVM is disabled from NMI - * context between reading EFER and executing STGI. In that - * case, GIF must already be set, otherwise the NMI would have - * been blocked, so just eat the fault. - */ - asm_volatile_goto("1: stgi\n\t" - _ASM_EXTABLE(1b, %l[fault]) - ::: "memory" : fault); -fault: - wrmsrl(MSR_EFER, efer & ~EFER_SVME); - } -} - -#endif /* _ASM_X86_VIRTEX_H */ diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 9e449167e71bb..47f9c7156609c 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -42,8 +42,6 @@ #include #include -#include - #include #include "trace.h" @@ -582,9 +580,32 @@ out: preempt_enable(); } +static inline void kvm_cpu_svm_disable(void) +{ + uint64_t efer; + + wrmsrl(MSR_VM_HSAVE_PA, 0); + rdmsrl(MSR_EFER, efer); + if (efer & EFER_SVME) { + /* + * Force GIF=1 prior to disabling SVM to ensure INIT and NMI + * aren't blocked, e.g. if a fatal error occurred between CLGI + * and STGI. Note, STGI may #UD if SVM is disabled from NMI + * context between reading EFER and executing STGI. In that + * case, GIF must already be set, otherwise the NMI would have + * been blocked, so just eat the fault. + */ + asm_volatile_goto("1: stgi\n\t" + _ASM_EXTABLE(1b, %l[fault]) + ::: "memory" : fault); +fault: + wrmsrl(MSR_EFER, efer & ~EFER_SVME); + } +} + static void svm_emergency_disable(void) { - cpu_svm_disable(); + kvm_cpu_svm_disable(); } static void svm_hardware_disable(void) @@ -593,7 +614,7 @@ static void svm_hardware_disable(void) if (tsc_scaling) __svm_write_tsc_multiplier(SVM_TSC_RATIO_DEFAULT); - cpu_svm_disable(); + kvm_cpu_svm_disable(); amd_pmu_disable_virt(); } -- GitLab From 6ae44e012f4c35fb67bc61bd0bf1b3c5f504d931 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 21 Jul 2023 13:18:57 -0700 Subject: [PATCH 0812/3445] KVM: x86: Force kvm_rebooting=true during emergency reboot/crash Set kvm_rebooting when virtualization is disabled in an emergency so that KVM eats faults on virtualization instructions even if kvm_reboot() isn't reached. Reviewed-by: Kai Huang Link: https://lore.kernel.org/r/20230721201859.2307736-18-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/svm.c | 2 ++ arch/x86/kvm/vmx/vmx.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 47f9c7156609c..8d1b3c8016290 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -605,6 +605,8 @@ fault: static void svm_emergency_disable(void) { + kvm_rebooting = true; + kvm_cpu_svm_disable(); } diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index ff0eced7d2abe..415665c40a39f 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -752,6 +752,8 @@ static void vmx_emergency_disable(void) int cpu = raw_smp_processor_id(); struct loaded_vmcs *v; + kvm_rebooting = true; + list_for_each_entry(v, &per_cpu(loaded_vmcss_on_cpu, cpu), loaded_vmcss_on_cpu_link) vmcs_clear(v->vmcs); -- GitLab From 2e6b9bd49b702c4a52278e35202354b709021116 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 21 Jul 2023 13:18:58 -0700 Subject: [PATCH 0813/3445] KVM: SVM: Use "standard" stgi() helper when disabling SVM Now that kvm_rebooting is guaranteed to be true prior to disabling SVM in an emergency, use the existing stgi() helper instead of open coding STGI. In effect, eat faults on STGI if and only if kvm_rebooting==true. Link: https://lore.kernel.org/r/20230721201859.2307736-19-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/svm.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 8d1b3c8016290..4785d780cce3b 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -588,17 +588,10 @@ static inline void kvm_cpu_svm_disable(void) rdmsrl(MSR_EFER, efer); if (efer & EFER_SVME) { /* - * Force GIF=1 prior to disabling SVM to ensure INIT and NMI - * aren't blocked, e.g. if a fatal error occurred between CLGI - * and STGI. Note, STGI may #UD if SVM is disabled from NMI - * context between reading EFER and executing STGI. In that - * case, GIF must already be set, otherwise the NMI would have - * been blocked, so just eat the fault. + * Force GIF=1 prior to disabling SVM, e.g. to ensure INIT and + * NMI aren't blocked. */ - asm_volatile_goto("1: stgi\n\t" - _ASM_EXTABLE(1b, %l[fault]) - ::: "memory" : fault); -fault: + stgi(); wrmsrl(MSR_EFER, efer & ~EFER_SVME); } } -- GitLab From a788fbb763b5001f67f2ecdf207a357f9b12838f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 21 Jul 2023 13:18:59 -0700 Subject: [PATCH 0814/3445] KVM: VMX: Skip VMCLEAR logic during emergency reboots if CR4.VMXE=0 Bail from vmx_emergency_disable() without processing the list of loaded VMCSes if CR4.VMXE=0, i.e. if the CPU can't be post-VMXON. It should be impossible for the list to have entries if VMX is already disabled, and even if that invariant doesn't hold, VMCLEAR will #UD anyways, i.e. processing the list is pointless even if it somehow isn't empty. Assuming no existing KVM bugs, this should be a glorified nop. The primary motivation for the change is to avoid having code that looks like it does VMCLEAR, but then skips VMXON, which is nonsensical. Suggested-by: Kai Huang Reviewed-by: Kai Huang Link: https://lore.kernel.org/r/20230721201859.2307736-20-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 415665c40a39f..83338872a39f0 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -754,12 +754,20 @@ static void vmx_emergency_disable(void) kvm_rebooting = true; + /* + * Note, CR4.VMXE can be _cleared_ in NMI context, but it can only be + * set in task context. If this races with VMX is disabled by an NMI, + * VMCLEAR and VMXOFF may #UD, but KVM will eat those faults due to + * kvm_rebooting set. + */ + if (!(__read_cr4() & X86_CR4_VMXE)) + return; + list_for_each_entry(v, &per_cpu(loaded_vmcss_on_cpu, cpu), loaded_vmcss_on_cpu_link) vmcs_clear(v->vmcs); - if (__read_cr4() & X86_CR4_VMXE) - kvm_cpu_vmxoff(); + kvm_cpu_vmxoff(); } static void __loaded_vmcs_clear(void *arg) -- GitLab From 99b668545356115e11a6cca519361c8cfd02569e Mon Sep 17 00:00:00 2001 From: Tao Su Date: Wed, 2 Aug 2023 10:29:54 +0800 Subject: [PATCH 0815/3445] KVM: x86: Advertise AMX-COMPLEX CPUID to userspace Latest Intel platform GraniteRapids-D introduces AMX-COMPLEX, which adds two instructions to perform matrix multiplication of two tiles containing complex elements and accumulate the results into a packed single precision tile. AMX-COMPLEX is enumerated via CPUID.(EAX=7,ECX=1):EDX[bit 8] Advertise AMX_COMPLEX if it's supported in hardware. There are no VMX controls for the feature, i.e. the instructions can't be interecepted, and KVM advertises base AMX in CPUID if AMX is supported in hardware, even if KVM doesn't advertise AMX as being supported in XCR0, e.g. because the process didn't opt-in to allocating tile data. Signed-off-by: Tao Su Reviewed-by: Xiaoyao Li Link: https://lore.kernel.org/r/20230802022954.193843-1-tao1.su@linux.intel.com [sean: tweak last paragraph of changelog] Signed-off-by: Sean Christopherson --- arch/x86/kvm/cpuid.c | 3 ++- arch/x86/kvm/reverse_cpuid.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index ad6566636c22d..5a88affb2e1a4 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -647,7 +647,8 @@ void kvm_set_cpu_caps(void) ); kvm_cpu_cap_init_kvm_defined(CPUID_7_1_EDX, - F(AVX_VNNI_INT8) | F(AVX_NE_CONVERT) | F(PREFETCHITI) + F(AVX_VNNI_INT8) | F(AVX_NE_CONVERT) | F(PREFETCHITI) | + F(AMX_COMPLEX) ); kvm_cpu_cap_mask(CPUID_D_1_EAX, diff --git a/arch/x86/kvm/reverse_cpuid.h b/arch/x86/kvm/reverse_cpuid.h index 56cbdb24400ae..b816506783755 100644 --- a/arch/x86/kvm/reverse_cpuid.h +++ b/arch/x86/kvm/reverse_cpuid.h @@ -43,6 +43,7 @@ enum kvm_only_cpuid_leafs { /* Intel-defined sub-features, CPUID level 0x00000007:1 (EDX) */ #define X86_FEATURE_AVX_VNNI_INT8 KVM_X86_FEATURE(CPUID_7_1_EDX, 4) #define X86_FEATURE_AVX_NE_CONVERT KVM_X86_FEATURE(CPUID_7_1_EDX, 5) +#define X86_FEATURE_AMX_COMPLEX KVM_X86_FEATURE(CPUID_7_1_EDX, 8) #define X86_FEATURE_PREFETCHITI KVM_X86_FEATURE(CPUID_7_1_EDX, 14) /* CPUID level 0x80000007 (EDX). */ -- GitLab From 95f5c19c8c04a81477b73b478d10d4eda7aa2f69 Mon Sep 17 00:00:00 2001 From: Han Dapeng Date: Thu, 3 Aug 2023 23:55:27 +0800 Subject: [PATCH 0816/3445] Documentation: cgroup-v2.rst: Correct number of stats entries Signed-off-by: Han Dapeng Signed-off-by: Tejun Heo --- Documentation/admin-guide/cgroup-v2.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst index 4ef8901911961..b26b5274eaaf1 100644 --- a/Documentation/admin-guide/cgroup-v2.rst +++ b/Documentation/admin-guide/cgroup-v2.rst @@ -1045,7 +1045,7 @@ All time durations are in microseconds. - user_usec - system_usec - and the following three when the controller is enabled: + and the following five when the controller is enabled: - nr_periods - nr_throttled -- GitLab From 7f828eacc4bbfd3ceea8ea17051858262fe04122 Mon Sep 17 00:00:00 2001 From: Miaohe Lin Date: Thu, 3 Aug 2023 19:57:02 +0800 Subject: [PATCH 0817/3445] cgroup: fix obsolete function name in cgroup_destroy_locked() Since commit e76ecaeef65c ("cgroup: use cgroup_kn_lock_live() in other cgroup kernfs methods"), cgroup_kn_lock_live() is used in cgroup kernfs methods. Update corresponding comment. Signed-off-by: Miaohe Lin Acked-by: Johannes Weiner Signed-off-by: Tejun Heo --- kernel/cgroup/cgroup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index f9cde56cf9475..85e723abd9e29 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -5871,7 +5871,7 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) /* * Mark @cgrp and the associated csets dead. The former prevents * further task migration and child creation by disabling - * cgroup_lock_live_group(). The latter makes the csets ignored by + * cgroup_kn_lock_live(). The latter makes the csets ignored by * the migration path. */ cgrp->self.flags &= ~CSS_ONLINE; -- GitLab From 7cafe9b8e22bb3d77f130c461aedf6868c4aaf58 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 18:15:48 -0700 Subject: [PATCH 0818/3445] KVM: nSVM: Check instead of asserting on nested TSC scaling support Check for nested TSC scaling support on nested SVM VMRUN instead of asserting that TSC scaling is exposed to L1 if L1's MSR_AMD64_TSC_RATIO has diverged from KVM's default. Userspace can trigger the WARN at will by writing the MSR and then updating guest CPUID to hide the feature (modifying guest CPUID is allowed anytime before KVM_RUN). E.g. hacking KVM's state_test selftest to do vcpu_set_msr(vcpu, MSR_AMD64_TSC_RATIO, 0); vcpu_clear_cpuid_feature(vcpu, X86_FEATURE_TSCRATEMSR); after restoring state in a new VM+vCPU yields an endless supply of: ------------[ cut here ]------------ WARNING: CPU: 164 PID: 62565 at arch/x86/kvm/svm/nested.c:699 nested_vmcb02_prepare_control+0x3d6/0x3f0 [kvm_amd] Call Trace: enter_svm_guest_mode+0x114/0x560 [kvm_amd] nested_svm_vmrun+0x260/0x330 [kvm_amd] vmrun_interception+0x29/0x30 [kvm_amd] svm_invoke_exit_handler+0x35/0x100 [kvm_amd] svm_handle_exit+0xe7/0x180 [kvm_amd] kvm_arch_vcpu_ioctl_run+0x1eab/0x2570 [kvm] kvm_vcpu_ioctl+0x4c9/0x5b0 [kvm] __se_sys_ioctl+0x7a/0xc0 __x64_sys_ioctl+0x21/0x30 do_syscall_64+0x41/0x90 entry_SYSCALL_64_after_hwframe+0x63/0xcd RIP: 0033:0x45ca1b Note, the nested #VMEXIT path has the same flaw, but needs a different fix and will be handled separately. Fixes: 5228eb96a487 ("KVM: x86: nSVM: implement nested TSC scaling") Cc: Maxim Levitsky Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20230729011608.1065019-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/nested.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index 96936ddf1b3c5..0b90f5cf9df38 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -695,10 +695,9 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm, vmcb02->control.tsc_offset = vcpu->arch.tsc_offset; - if (svm->tsc_ratio_msr != kvm_caps.default_tsc_scaling_ratio) { - WARN_ON(!svm->tsc_scaling_enabled); + if (svm->tsc_scaling_enabled && + svm->tsc_ratio_msr != kvm_caps.default_tsc_scaling_ratio) nested_svm_update_tsc_ratio_msr(vcpu); - } vmcb02->control.int_ctl = (svm->nested.ctl.int_ctl & int_ctl_vmcb12_bits) | -- GitLab From 0c94e2468491cbf0754f49a5136ab51294a96b69 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 18:15:49 -0700 Subject: [PATCH 0819/3445] KVM: nSVM: Load L1's TSC multiplier based on L1 state, not L2 state When emulating nested VM-Exit, load L1's TSC multiplier if L1's desired ratio doesn't match the current ratio, not if the ratio L1 is using for L2 diverges from the default. Functionally, the end result is the same as KVM will run L2 with L1's multiplier if L2's multiplier is the default, i.e. checking that L1's multiplier is loaded is equivalent to checking if L2 has a non-default multiplier. However, the assertion that TSC scaling is exposed to L1 is flawed, as userspace can trigger the WARN at will by writing the MSR and then updating guest CPUID to hide the feature (modifying guest CPUID is allowed anytime before KVM_RUN). E.g. hacking KVM's state_test selftest to do vcpu_set_msr(vcpu, MSR_AMD64_TSC_RATIO, 0); vcpu_clear_cpuid_feature(vcpu, X86_FEATURE_TSCRATEMSR); after restoring state in a new VM+vCPU yields an endless supply of: ------------[ cut here ]------------ WARNING: CPU: 10 PID: 206939 at arch/x86/kvm/svm/nested.c:1105 nested_svm_vmexit+0x6af/0x720 [kvm_amd] Call Trace: nested_svm_exit_handled+0x102/0x1f0 [kvm_amd] svm_handle_exit+0xb9/0x180 [kvm_amd] kvm_arch_vcpu_ioctl_run+0x1eab/0x2570 [kvm] kvm_vcpu_ioctl+0x4c9/0x5b0 [kvm] ? trace_hardirqs_off+0x4d/0xa0 __se_sys_ioctl+0x7a/0xc0 __x64_sys_ioctl+0x21/0x30 do_syscall_64+0x41/0x90 entry_SYSCALL_64_after_hwframe+0x63/0xcd Unlike the nested VMRUN path, hoisting the svm->tsc_scaling_enabled check into the if-statement is wrong as KVM needs to ensure L1's multiplier is loaded in the above scenario. Alternatively, the WARN_ON() could simply be deleted, but that would make KVM's behavior even more subtle, e.g. it's not immediately obvious why it's safe to write MSR_AMD64_TSC_RATIO when checking only tsc_ratio_msr. Fixes: 5228eb96a487 ("KVM: x86: nSVM: implement nested TSC scaling") Cc: Maxim Levitsky Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20230729011608.1065019-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/nested.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index 0b90f5cf9df38..c66c823ae222a 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -1100,8 +1100,8 @@ int nested_svm_vmexit(struct vcpu_svm *svm) vmcb_mark_dirty(vmcb01, VMCB_INTERCEPTS); } - if (svm->tsc_ratio_msr != kvm_caps.default_tsc_scaling_ratio) { - WARN_ON(!svm->tsc_scaling_enabled); + if (kvm_caps.has_tsc_control && + vcpu->arch.tsc_scaling_ratio != vcpu->arch.l1_tsc_scaling_ratio) { vcpu->arch.tsc_scaling_ratio = vcpu->arch.l1_tsc_scaling_ratio; __svm_write_tsc_multiplier(vcpu->arch.tsc_scaling_ratio); } -- GitLab From c0dc39bd2c584879748dfd1321f8541d1cbeb9b8 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 18:15:50 -0700 Subject: [PATCH 0820/3445] KVM: nSVM: Use the "outer" helper for writing multiplier to MSR_AMD64_TSC_RATIO When emulating nested SVM transitions, use the outer helper for writing the TSC multiplier for L2. Using the inner helper only for one-off cases, i.e. for paths where KVM is NOT emulating or modifying vCPU state, will allow for multiple cleanups: - Explicitly disabling preemption only in the outer helper - Getting the multiplier from the vCPU field in the outer helper - Skipping the WRMSR in the outer helper if guest state isn't loaded Opportunistically delete an extra newline. No functional change intended. Link: https://lore.kernel.org/r/20230729011608.1065019-4-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/nested.c | 4 ++-- arch/x86/kvm/svm/svm.c | 5 ++--- arch/x86/kvm/svm/svm.h | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index c66c823ae222a..5d5a1d7832fb2 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -1103,7 +1103,7 @@ int nested_svm_vmexit(struct vcpu_svm *svm) if (kvm_caps.has_tsc_control && vcpu->arch.tsc_scaling_ratio != vcpu->arch.l1_tsc_scaling_ratio) { vcpu->arch.tsc_scaling_ratio = vcpu->arch.l1_tsc_scaling_ratio; - __svm_write_tsc_multiplier(vcpu->arch.tsc_scaling_ratio); + svm_write_tsc_multiplier(vcpu, vcpu->arch.tsc_scaling_ratio); } svm->nested.ctl.nested_cr3 = 0; @@ -1536,7 +1536,7 @@ void nested_svm_update_tsc_ratio_msr(struct kvm_vcpu *vcpu) vcpu->arch.tsc_scaling_ratio = kvm_calc_nested_tsc_multiplier(vcpu->arch.l1_tsc_scaling_ratio, svm->tsc_ratio_msr); - __svm_write_tsc_multiplier(vcpu->arch.tsc_scaling_ratio); + svm_write_tsc_multiplier(vcpu, vcpu->arch.tsc_scaling_ratio); } /* Inverse operation of nested_copy_vmcb_control_to_cache(). asid is copied too. */ diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 4785d780cce3b..7217f7532df91 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -567,7 +567,7 @@ static int svm_check_processor_compat(void) return 0; } -void __svm_write_tsc_multiplier(u64 multiplier) +static void __svm_write_tsc_multiplier(u64 multiplier) { preempt_disable(); @@ -1150,12 +1150,11 @@ static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) vmcb_mark_dirty(svm->vmcb, VMCB_INTERCEPTS); } -static void svm_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 multiplier) +void svm_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 multiplier) { __svm_write_tsc_multiplier(multiplier); } - /* Evaluate instruction intercepts that depend on guest CPUID features. */ static void svm_recalc_instruction_intercepts(struct kvm_vcpu *vcpu, struct vcpu_svm *svm) diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 18af7e712a5ae..7132c0a048179 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -658,7 +658,7 @@ int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr, bool has_error_code, u32 error_code); int nested_svm_exit_special(struct vcpu_svm *svm); void nested_svm_update_tsc_ratio_msr(struct kvm_vcpu *vcpu); -void __svm_write_tsc_multiplier(u64 multiplier); +void svm_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 multiplier); void nested_copy_vmcb_control_to_cache(struct vcpu_svm *svm, struct vmcb_control_area *control); void nested_copy_vmcb_save_to_cache(struct vcpu_svm *svm, -- GitLab From 229725acfaea0dd81f245aec40986dc766de40fa Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 18:15:51 -0700 Subject: [PATCH 0821/3445] KVM: SVM: Clean up preemption toggling related to MSR_AMD64_TSC_RATIO Explicitly disable preemption when writing MSR_AMD64_TSC_RATIO only in the "outer" helper, as all direct callers of the "inner" helper now run with preemption already disabled. And that isn't a coincidence, as the outer helper requires a vCPU and is intended to be used when modifying guest state and/or emulating guest instructions, which are typically done with preemption enabled. Direct use of the inner helper should be extremely limited, as the only time KVM should modify MSR_AMD64_TSC_RATIO without a vCPU is when sanitizing the MSR for a specific pCPU (currently done when {en,dis}abling disabling SVM). The other direct caller is svm_prepare_switch_to_guest(), which does have a vCPU, but is a one-off special case: KVM is about to enter the guest on a specific pCPU and thus must have preemption disabled. Link: https://lore.kernel.org/r/20230729011608.1065019-5-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/svm.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 7217f7532df91..b66af2966ec79 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -569,15 +569,11 @@ static int svm_check_processor_compat(void) static void __svm_write_tsc_multiplier(u64 multiplier) { - preempt_disable(); - if (multiplier == __this_cpu_read(current_tsc_ratio)) - goto out; + return; wrmsrl(MSR_AMD64_TSC_RATIO, multiplier); __this_cpu_write(current_tsc_ratio, multiplier); -out: - preempt_enable(); } static inline void kvm_cpu_svm_disable(void) @@ -1152,7 +1148,9 @@ static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) void svm_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 multiplier) { + preempt_disable(); __svm_write_tsc_multiplier(multiplier); + preempt_enable(); } /* Evaluate instruction intercepts that depend on guest CPUID features. */ -- GitLab From 2d63699099ac1fad13a0dbf8538faf4127c062e8 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 18:15:52 -0700 Subject: [PATCH 0822/3445] KVM: x86: Always write vCPU's current TSC offset/ratio in vendor hooks Drop the @offset and @multiplier params from the kvm_x86_ops hooks for propagating TSC offsets/multipliers into hardware, and instead have the vendor implementations pull the information directly from the vCPU structure. The respective vCPU fields _must_ be written at the same time in order to maintain consistent state, i.e. it's not random luck that the value passed in by all callers is grabbed from the vCPU. Explicitly grabbing the value from the vCPU field in SVM's implementation in particular will allow for additional cleanup without introducing even more subtle dependencies. Specifically, SVM can skip the WRMSR if guest state isn't loaded, i.e. svm_prepare_switch_to_guest() will load the correct value for the vCPU prior to entering the guest. This also reconciles KVM's handling of related values that are stored in the vCPU, as svm_write_tsc_offset() already assumes/requires the caller to have updated l1_tsc_offset. Link: https://lore.kernel.org/r/20230729011608.1065019-6-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 4 ++-- arch/x86/kvm/svm/nested.c | 4 ++-- arch/x86/kvm/svm/svm.c | 8 ++++---- arch/x86/kvm/svm/svm.h | 2 +- arch/x86/kvm/vmx/vmx.c | 8 ++++---- arch/x86/kvm/x86.c | 5 ++--- 6 files changed, 15 insertions(+), 16 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 28bd38303d704..dad9331c5270e 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1654,8 +1654,8 @@ struct kvm_x86_ops { u64 (*get_l2_tsc_offset)(struct kvm_vcpu *vcpu); u64 (*get_l2_tsc_multiplier)(struct kvm_vcpu *vcpu); - void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset); - void (*write_tsc_multiplier)(struct kvm_vcpu *vcpu, u64 multiplier); + void (*write_tsc_offset)(struct kvm_vcpu *vcpu); + void (*write_tsc_multiplier)(struct kvm_vcpu *vcpu); /* * Retrieve somewhat arbitrary exit information. Intended to diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index 5d5a1d7832fb2..3342cc4a51892 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -1103,7 +1103,7 @@ int nested_svm_vmexit(struct vcpu_svm *svm) if (kvm_caps.has_tsc_control && vcpu->arch.tsc_scaling_ratio != vcpu->arch.l1_tsc_scaling_ratio) { vcpu->arch.tsc_scaling_ratio = vcpu->arch.l1_tsc_scaling_ratio; - svm_write_tsc_multiplier(vcpu, vcpu->arch.tsc_scaling_ratio); + svm_write_tsc_multiplier(vcpu); } svm->nested.ctl.nested_cr3 = 0; @@ -1536,7 +1536,7 @@ void nested_svm_update_tsc_ratio_msr(struct kvm_vcpu *vcpu) vcpu->arch.tsc_scaling_ratio = kvm_calc_nested_tsc_multiplier(vcpu->arch.l1_tsc_scaling_ratio, svm->tsc_ratio_msr); - svm_write_tsc_multiplier(vcpu, vcpu->arch.tsc_scaling_ratio); + svm_write_tsc_multiplier(vcpu); } /* Inverse operation of nested_copy_vmcb_control_to_cache(). asid is copied too. */ diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index b66af2966ec79..2542066652a34 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -1137,19 +1137,19 @@ static u64 svm_get_l2_tsc_multiplier(struct kvm_vcpu *vcpu) return svm->tsc_ratio_msr; } -static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) +static void svm_write_tsc_offset(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); svm->vmcb01.ptr->control.tsc_offset = vcpu->arch.l1_tsc_offset; - svm->vmcb->control.tsc_offset = offset; + svm->vmcb->control.tsc_offset = vcpu->arch.tsc_offset; vmcb_mark_dirty(svm->vmcb, VMCB_INTERCEPTS); } -void svm_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 multiplier) +void svm_write_tsc_multiplier(struct kvm_vcpu *vcpu) { preempt_disable(); - __svm_write_tsc_multiplier(multiplier); + __svm_write_tsc_multiplier(vcpu->arch.tsc_scaling_ratio); preempt_enable(); } diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 7132c0a048179..5829a18018623 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -658,7 +658,7 @@ int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr, bool has_error_code, u32 error_code); int nested_svm_exit_special(struct vcpu_svm *svm); void nested_svm_update_tsc_ratio_msr(struct kvm_vcpu *vcpu); -void svm_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 multiplier); +void svm_write_tsc_multiplier(struct kvm_vcpu *vcpu); void nested_copy_vmcb_control_to_cache(struct vcpu_svm *svm, struct vmcb_control_area *control); void nested_copy_vmcb_save_to_cache(struct vcpu_svm *svm, diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 83338872a39f0..3235998ca2619 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -1898,14 +1898,14 @@ u64 vmx_get_l2_tsc_multiplier(struct kvm_vcpu *vcpu) return kvm_caps.default_tsc_scaling_ratio; } -static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) +static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu) { - vmcs_write64(TSC_OFFSET, offset); + vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset); } -static void vmx_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 multiplier) +static void vmx_write_tsc_multiplier(struct kvm_vcpu *vcpu) { - vmcs_write64(TSC_MULTIPLIER, multiplier); + vmcs_write64(TSC_MULTIPLIER, vcpu->arch.tsc_scaling_ratio); } /* diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a1b13d2d1d719..80ec33fc823be 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2613,7 +2613,7 @@ static void kvm_vcpu_write_tsc_offset(struct kvm_vcpu *vcpu, u64 l1_offset) else vcpu->arch.tsc_offset = l1_offset; - static_call(kvm_x86_write_tsc_offset)(vcpu, vcpu->arch.tsc_offset); + static_call(kvm_x86_write_tsc_offset)(vcpu); } static void kvm_vcpu_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 l1_multiplier) @@ -2629,8 +2629,7 @@ static void kvm_vcpu_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 l1_multipli vcpu->arch.tsc_scaling_ratio = l1_multiplier; if (kvm_caps.has_tsc_control) - static_call(kvm_x86_write_tsc_multiplier)( - vcpu, vcpu->arch.tsc_scaling_ratio); + static_call(kvm_x86_write_tsc_multiplier)(vcpu); } static inline bool kvm_check_tsc_unstable(void) -- GitLab From 223f93d4d88aedc02bdcc92b3734e76f707812f3 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 28 Jul 2023 18:15:53 -0700 Subject: [PATCH 0823/3445] KVM: nSVM: Skip writes to MSR_AMD64_TSC_RATIO if guest state isn't loaded Skip writes to MSR_AMD64_TSC_RATIO that are done in the context of a vCPU if guest state isn't loaded, i.e. if KVM will update MSR_AMD64_TSC_RATIO during svm_prepare_switch_to_guest() before entering the guest. Checking guest_state_loaded may or may not be a net positive for performance as the current_tsc_ratio cache will optimize away duplicate WRMSRs in the vast majority of scenarios. However, the cost of the check is negligible, and the real motivation is to document that KVM needs to load the vCPU's value only when running the vCPU. Link: https://lore.kernel.org/r/20230729011608.1065019-7-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/svm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 2542066652a34..6d8932e057536 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -1149,7 +1149,8 @@ static void svm_write_tsc_offset(struct kvm_vcpu *vcpu) void svm_write_tsc_multiplier(struct kvm_vcpu *vcpu) { preempt_disable(); - __svm_write_tsc_multiplier(vcpu->arch.tsc_scaling_ratio); + if (to_svm(vcpu)->guest_state_loaded) + __svm_write_tsc_multiplier(vcpu->arch.tsc_scaling_ratio); preempt_enable(); } -- GitLab From e9714c22c1a8238a85d069b1517941fc723312f7 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Mon, 31 Jul 2023 14:58:36 +0300 Subject: [PATCH 0824/3445] mtd: fix use-after-free in mtd release I case of partition device_unregister() in mtd_device_release() calls mtd_release() which frees mtd_info structure for partition. All code after device_unregister in mtd_device_release thus uses already freed memory. Move part of code to mtd_release() and restict mtd->dev cleanup to non-partion object. For partition object such cleanup have no sense as partition mtd_info is removed. Cc: Miquel Raynal Cc: Zhang Xiaoxu Fixes: 19bfa9ebebb5 ("mtd: use refcount to prevent corruption") Reviewed-by: Tomas Winkler Signed-off-by: Alexander Usyskin Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230731115836.542747-1-alexander.usyskin@intel.com --- drivers/mtd/mtdcore.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 2466ea4664668..46f15f6764916 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -93,6 +93,9 @@ static void mtd_release(struct device *dev) struct mtd_info *mtd = dev_get_drvdata(dev); dev_t index = MTD_DEVT(mtd->index); + idr_remove(&mtd_idr, mtd->index); + of_node_put(mtd_get_of_node(mtd)); + if (mtd_is_partition(mtd)) release_mtd_partition(mtd); @@ -103,6 +106,7 @@ static void mtd_release(struct device *dev) static void mtd_device_release(struct kref *kref) { struct mtd_info *mtd = container_of(kref, struct mtd_info, refcnt); + bool is_partition = mtd_is_partition(mtd); debugfs_remove_recursive(mtd->dbg.dfs_dir); @@ -111,11 +115,13 @@ static void mtd_device_release(struct kref *kref) device_unregister(&mtd->dev); - /* Clear dev so mtd can be safely re-registered later if desired */ - memset(&mtd->dev, 0, sizeof(mtd->dev)); - - idr_remove(&mtd_idr, mtd->index); - of_node_put(mtd_get_of_node(mtd)); + /* + * Clear dev so mtd can be safely re-registered later if desired. + * Should not be done for partition, + * as it was already destroyed in device_unregister(). + */ + if (!is_partition) + memset(&mtd->dev, 0, sizeof(mtd->dev)); module_put(THIS_MODULE); } -- GitLab From 264725e35fbc3b67e053a405e022393a6017e6da Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Mon, 31 Jul 2023 11:09:03 +0200 Subject: [PATCH 0825/3445] mtd: Clean refcounting with MTD_PARTITIONED_MASTER The logic is way too convoluted, let's clean the kref_get/put section to clarify what this block does when using CONFIG_MTD_PARTITIONED_MASTER: - Iterate through all the parent mtd devices - Grab a reference over them all but the master - Only grab the master whith CONFIG_MTD_PARTITIONED_MASTER Same logic must apply in the put path, otherwise it would be broken. Cc: Tomas Winkler Cc: Alexander Usyskin Cc: Zhang Xiaoxu Fixes: 19bfa9ebebb5 ("mtd: use refcount to prevent corruption") Signed-off-by: Miquel Raynal Tested-by: Alexander Usyskin Link: https://lore.kernel.org/linux-mtd/20230731090903.770277-1-miquel.raynal@bootlin.com --- drivers/mtd/mtdcore.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 46f15f6764916..9bd661be3ae93 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -1247,14 +1247,15 @@ int __get_mtd_device(struct mtd_info *mtd) return -ENODEV; } - kref_get(&mtd->refcnt); - - while (mtd->parent) { - if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) || mtd->parent != master) - kref_get(&mtd->parent->refcnt); + while (mtd) { + if (mtd != master) + kref_get(&mtd->refcnt); mtd = mtd->parent; } + if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) + kref_get(&master->refcnt); + return 0; } EXPORT_SYMBOL_GPL(__get_mtd_device); @@ -1338,10 +1339,12 @@ void __put_mtd_device(struct mtd_info *mtd) { struct mtd_info *master = mtd_get_master(mtd); - while (mtd != master) { + while (mtd) { + /* kref_put() can relese mtd, so keep a reference mtd->parent */ struct mtd_info *parent = mtd->parent; - kref_put(&mtd->refcnt, mtd_device_release); + if (mtd != master) + kref_put(&mtd->refcnt, mtd_device_release); mtd = parent; } -- GitLab From 31cbe3a7e217ba8ec482ae821092e57d96275d5b Mon Sep 17 00:00:00 2001 From: Li Zetao Date: Wed, 2 Aug 2023 09:35:00 +0800 Subject: [PATCH 0826/3445] mtd: rawnand: brcmnand: Use devm_platform_ioremap_resource_byname() Convert platform_get_resource_byname() + devm_ioremap_resource() to a single call to devm_platform_ioremap_resource_byname(), as this is exactly what this function does. Signed-off-by: Li Zetao Reviewed-by: Florian Fainelli Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230802013500.1030853-1-lizetao1@huawei.com --- drivers/mtd/nand/raw/brcmnand/bcm63138_nand.c | 4 +--- drivers/mtd/nand/raw/brcmnand/iproc_nand.c | 7 ++----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/raw/brcmnand/bcm63138_nand.c b/drivers/mtd/nand/raw/brcmnand/bcm63138_nand.c index 71ddcc611f6e4..9596629000f41 100644 --- a/drivers/mtd/nand/raw/brcmnand/bcm63138_nand.c +++ b/drivers/mtd/nand/raw/brcmnand/bcm63138_nand.c @@ -61,15 +61,13 @@ static int bcm63138_nand_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct bcm63138_nand_soc *priv; struct brcmnand_soc *soc; - struct resource *res; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; soc = &priv->soc; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand-int-base"); - priv->base = devm_ioremap_resource(dev, res); + priv->base = devm_platform_ioremap_resource_byname(pdev, "nand-int-base"); if (IS_ERR(priv->base)) return PTR_ERR(priv->base); diff --git a/drivers/mtd/nand/raw/brcmnand/iproc_nand.c b/drivers/mtd/nand/raw/brcmnand/iproc_nand.c index d32950847a62e..089c70fc6edfc 100644 --- a/drivers/mtd/nand/raw/brcmnand/iproc_nand.c +++ b/drivers/mtd/nand/raw/brcmnand/iproc_nand.c @@ -103,7 +103,6 @@ static int iproc_nand_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct iproc_nand_soc *priv; struct brcmnand_soc *soc; - struct resource *res; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -112,13 +111,11 @@ static int iproc_nand_probe(struct platform_device *pdev) spin_lock_init(&priv->idm_lock); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-idm"); - priv->idm_base = devm_ioremap_resource(dev, res); + priv->idm_base = devm_platform_ioremap_resource_byname(pdev, "iproc-idm"); if (IS_ERR(priv->idm_base)) return PTR_ERR(priv->idm_base); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-ext"); - priv->ext_base = devm_ioremap_resource(dev, res); + priv->ext_base = devm_platform_ioremap_resource_byname(pdev, "iproc-ext"); if (IS_ERR(priv->ext_base)) return PTR_ERR(priv->ext_base); -- GitLab From 3549fecd10d24bcf9840ba2f7d6a0b5f57feed6f Mon Sep 17 00:00:00 2001 From: Zhu Wang Date: Thu, 3 Aug 2023 16:50:56 +0800 Subject: [PATCH 0827/3445] mtd: rawnand: vf610_nfc: Do not check 0 for platform_get_irq() Since platform_get_irq() never returned zero, so it need not to check whether it returned zero, and we use the return error code of platform_get_irq() to replace the current return error code, for that platform_get_irq() may return -EINVAL or -ENXIO. Signed-off-by: Zhu Wang Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20230803085056.30888-1-wangzhu9@huawei.com --- drivers/mtd/nand/raw/vf610_nfc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c index 86522048e2714..dcdf33dbaef26 100644 --- a/drivers/mtd/nand/raw/vf610_nfc.c +++ b/drivers/mtd/nand/raw/vf610_nfc.c @@ -827,8 +827,8 @@ static int vf610_nfc_probe(struct platform_device *pdev) mtd->name = DRV_NAME; irq = platform_get_irq(pdev, 0); - if (irq <= 0) - return -EINVAL; + if (irq < 0) + return irq; nfc->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(nfc->regs)) -- GitLab From 7b9ef666f27afde43c047de2be2985b68ad9febe Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Thu, 3 Aug 2023 21:33:44 +0000 Subject: [PATCH 0828/3445] tomoyo: refactor deprecated strncpy `strncpy` is deprecated for use on NUL-terminated destination strings [1]. A suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on its destination buffer argument which is _not_ the case for `strncpy`! It should be noted that the destination buffer is zero-initialized and had a max length of `sizeof(dest) - 1`. There is likely _not_ a bug present in the current implementation. However, by switching to `strscpy` we get the benefit of no longer needing the `- 1`'s from the string copy invocations on top of `strscpy` being a safer interface all together. [1]: www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [2]: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Signed-off-by: Tetsuo Handa --- security/tomoyo/domain.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index ac20c0bdff9dc..90b53500a236b 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -784,13 +784,12 @@ retry: if (!strcmp(domainname, "parent")) { char *cp; - strncpy(ee->tmp, old_domain->domainname->name, - TOMOYO_EXEC_TMPSIZE - 1); + strscpy(ee->tmp, old_domain->domainname->name, TOMOYO_EXEC_TMPSIZE); cp = strrchr(ee->tmp, ' '); if (cp) *cp = '\0'; } else if (*domainname == '<') - strncpy(ee->tmp, domainname, TOMOYO_EXEC_TMPSIZE - 1); + strscpy(ee->tmp, domainname, TOMOYO_EXEC_TMPSIZE); else snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", old_domain->domainname->name, domainname); -- GitLab From d5cda142d649c690fb0fcf1e29f3df63fbafc442 Mon Sep 17 00:00:00 2001 From: "Chengci.Xu" Date: Fri, 2 Jun 2023 17:02:21 +0800 Subject: [PATCH 0829/3445] dt-bindings: mediatek: mt8188: Add binding for MM & INFRA IOMMU Add descriptions for mt8188 IOMMU which also use ARM Short-Descriptor translation table format. In mt8188, there are two smi-common HW and IOMMU, one is for vdo(video output), the other is for vpp(video processing pipe). They connects with different smi-larbs, then some setting(larbid_remap) is different. Differentiate them with the compatible string. Something like this: IOMMU(VDO) IOMMU(VPP) | | SMI_COMMON_VDO SMI_COMMON_VPP --------------- ---------------- | | ... | | ... larb0 larb2 ... larb1 larb3 ... We also have an IOMMU that is for infra master like PCIe. And infra master don't have the larb and ports. Signed-off-by: Chengci.Xu Signed-off-by: Yong Wu Reviewed-by: AngeloGioacchino Del Regno Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230602090227.7264-2-yong.wu@mediatek.com Signed-off-by: Joerg Roedel --- .../bindings/iommu/mediatek,iommu.yaml | 12 +- .../memory/mediatek,mt8188-memory-port.h | 489 ++++++++++++++++++ 2 files changed, 500 insertions(+), 1 deletion(-) create mode 100644 include/dt-bindings/memory/mediatek,mt8188-memory-port.h diff --git a/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml b/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml index 5b6395bc10e0c..ea6b0f5f24de7 100644 --- a/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml +++ b/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml @@ -78,6 +78,9 @@ properties: - mediatek,mt8173-m4u # generation two - mediatek,mt8183-m4u # generation two - mediatek,mt8186-iommu-mm # generation two + - mediatek,mt8188-iommu-vdo # generation two + - mediatek,mt8188-iommu-vpp # generation two + - mediatek,mt8188-iommu-infra # generation two - mediatek,mt8192-m4u # generation two - mediatek,mt8195-iommu-vdo # generation two - mediatek,mt8195-iommu-vpp # generation two @@ -123,6 +126,7 @@ properties: description: | This is the mtk_m4u_id according to the HW. Specifies the mtk_m4u_id as defined in + dt-binding/memory/mediatek,mt8188-memory-port.h for mt8188, dt-binding/memory/mt2701-larb-port.h for mt2701 and mt7623, dt-binding/memory/mt2712-larb-port.h for mt2712, dt-binding/memory/mt6779-larb-port.h for mt6779, @@ -155,6 +159,8 @@ allOf: - mediatek,mt6795-m4u - mediatek,mt8173-m4u - mediatek,mt8186-iommu-mm + - mediatek,mt8188-iommu-vdo + - mediatek,mt8188-iommu-vpp - mediatek,mt8192-m4u - mediatek,mt8195-iommu-vdo - mediatek,mt8195-iommu-vpp @@ -168,6 +174,8 @@ allOf: compatible: enum: - mediatek,mt8186-iommu-mm + - mediatek,mt8188-iommu-vdo + - mediatek,mt8188-iommu-vpp - mediatek,mt8192-m4u - mediatek,mt8195-iommu-vdo - mediatek,mt8195-iommu-vpp @@ -194,7 +202,9 @@ allOf: properties: compatible: contains: - const: mediatek,mt8195-iommu-infra + enum: + - mediatek,mt8188-iommu-infra + - mediatek,mt8195-iommu-infra then: required: diff --git a/include/dt-bindings/memory/mediatek,mt8188-memory-port.h b/include/dt-bindings/memory/mediatek,mt8188-memory-port.h new file mode 100644 index 0000000000000..337ab11262af9 --- /dev/null +++ b/include/dt-bindings/memory/mediatek,mt8188-memory-port.h @@ -0,0 +1,489 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Chengci Xu + */ +#ifndef _DT_BINDINGS_MEMORY_MEDIATEK_MT8188_LARB_PORT_H_ +#define _DT_BINDINGS_MEMORY_MEDIATEK_MT8188_LARB_PORT_H_ + +#include + +/* + * MM IOMMU larbs: + * From below, for example larb11 has larb11a/larb11b/larb11c, + * the index of larb is not in order. So we reindexed these larbs from a + * software view. + */ +#define SMI_L0_ID 0 +#define SMI_L1_ID 1 +#define SMI_L2_ID 2 +#define SMI_L3_ID 3 +#define SMI_L4_ID 4 +#define SMI_L5_ID 5 +#define SMI_L6_ID 6 +#define SMI_L7_ID 7 +#define SMI_L9_ID 8 +#define SMI_L10_ID 9 +#define SMI_L11A_ID 10 +#define SMI_L11B_ID 11 +#define SMI_L11C_ID 12 +#define SMI_L12_ID 13 +#define SMI_L13_ID 14 +#define SMI_L14_ID 15 +#define SMI_L15_ID 16 +#define SMI_L16A_ID 17 +#define SMI_L16B_ID 18 +#define SMI_L17A_ID 19 +#define SMI_L17B_ID 20 +#define SMI_L19_ID 21 +#define SMI_L21_ID 22 +#define SMI_L23_ID 23 +#define SMI_L27_ID 24 +#define SMI_L28_ID 25 + +/* + * MM IOMMU supports 16GB dma address. We separate it to four ranges: + * 0 ~ 4G; 4G ~ 8G; 8G ~ 12G; 12G ~ 16G, we could adjust these masters + * locate in anyone region. BUT: + * a) Make sure all the ports inside a larb are in one range. + * b) The iova of any master can NOT cross the 4G/8G/12G boundary. + * + * This is the suggested mapping in this SoC: + * + * modules dma-address-region larbs-ports + * disp 0 ~ 4G larb0/1/2/3 + * vcodec 4G ~ 8G larb19(21)[1]/21(22)/23 + * cam/mdp 8G ~ 12G the other larbs. + * N/A 12G ~ 16G + * CCU0 0x24000_0000 ~ 0x243ff_ffff larb27(24): port 0/1 + * CCU1 0x24400_0000 ~ 0x247ff_ffff larb27(24): port 2/3 + * + * This SoC have two MM IOMMU HWs, this is the connected information: + * iommu-vdo: larb0/2/5/9/10/11A/11C/13/16B/17B/19/21 + * iommu-vpp: larb1/3/4/6/7/11B/12/14/15/16A/17A/23/27 + * + * [1]: This is larb19, but the index is 21 from the SW view. + */ + +/* MM IOMMU ports */ +/* LARB 0 -- VDO-0 */ +#define M4U_PORT_L0_DISP_RDMA1 MTK_M4U_ID(SMI_L0_ID, 0) +#define M4U_PORT_L0_DISP_WDMA0 MTK_M4U_ID(SMI_L0_ID, 1) +#define M4U_PORT_L0_DISP_OVL0_RDMA0 MTK_M4U_ID(SMI_L0_ID, 2) +#define M4U_PORT_L0_DISP_OVL0_RDMA1 MTK_M4U_ID(SMI_L0_ID, 3) +#define M4U_PORT_L0_DISP_OVL0_HDR MTK_M4U_ID(SMI_L0_ID, 4) +#define M4U_PORT_L0_DISP_POSTMASK0 MTK_M4U_ID(SMI_L0_ID, 5) +#define M4U_PORT_L0_DISP_FAKE_ENG0 MTK_M4U_ID(SMI_L0_ID, 6) + +/* LARB 1 -- VD0-0 */ +#define M4U_PORT_L1_DISP_RDMA0 MTK_M4U_ID(SMI_L1_ID, 0) +#define M4U_PORT_L1_DISP_WDMA1 MTK_M4U_ID(SMI_L1_ID, 1) +#define M4U_PORT_L1_DISP_OVL1_RDMA0 MTK_M4U_ID(SMI_L1_ID, 2) +#define M4U_PORT_L1_DISP_OVL1_RDMA1 MTK_M4U_ID(SMI_L1_ID, 3) +#define M4U_PORT_L1_DISP_OVL1_HDR MTK_M4U_ID(SMI_L1_ID, 4) +#define M4U_PORT_L1_DISP_WROT0 MTK_M4U_ID(SMI_L1_ID, 5) +#define M4U_PORT_L1_DISP_FAKE_ENG1 MTK_M4U_ID(SMI_L1_ID, 6) + +/* LARB 2 -- VDO-1 */ +#define M4U_PORT_L2_MDP_RDMA0 MTK_M4U_ID(SMI_L2_ID, 0) +#define M4U_PORT_L2_MDP_RDMA2 MTK_M4U_ID(SMI_L2_ID, 1) +#define M4U_PORT_L2_MDP_RDMA4 MTK_M4U_ID(SMI_L2_ID, 2) +#define M4U_PORT_L2_MDP_RDMA6 MTK_M4U_ID(SMI_L2_ID, 3) +#define M4U_PORT_L2_DISP_FAKE1 MTK_M4U_ID(SMI_L2_ID, 4) + +/* LARB 3 -- VDO-1 */ +#define M4U_PORT_L3_MDP_RDMA1 MTK_M4U_ID(SMI_L3_ID, 0) +#define M4U_PORT_L3_MDP_RDMA3 MTK_M4U_ID(SMI_L3_ID, 1) +#define M4U_PORT_L3_MDP_RDMA5 MTK_M4U_ID(SMI_L3_ID, 2) +#define M4U_PORT_L3_MDP_RDMA7 MTK_M4U_ID(SMI_L3_ID, 3) +#define M4U_PORT_L3_HDR_DS_SMI MTK_M4U_ID(SMI_L3_ID, 4) +#define M4U_PORT_L3_HDR_ADL_SMI MTK_M4U_ID(SMI_L3_ID, 5) +#define M4U_PORT_L3_DISP_FAKE1 MTK_M4U_ID(SMI_L3_ID, 6) + +/* LARB 4 -- VPP-0 */ +#define M4U_PORT_L4_MDP_RDMA MTK_M4U_ID(SMI_L4_ID, 0) +#define M4U_PORT_L4_MDP_FG MTK_M4U_ID(SMI_L4_ID, 1) +#define M4U_PORT_L4_MDP_OVL MTK_M4U_ID(SMI_L4_ID, 2) +#define M4U_PORT_L4_MDP_WROT MTK_M4U_ID(SMI_L4_ID, 3) +#define M4U_PORT_L4_FAKE_ENG MTK_M4U_ID(SMI_L4_ID, 4) +#define M4U_PORT_L4_DISP_RDMA MTK_M4U_ID(SMI_L4_ID, 5) +#define M4U_PORT_L4_DISP_WDMA MTK_M4U_ID(SMI_L4_ID, 6) + +/* LARB 5 -- VPP-1 */ +#define M4U_PORT_L5_SVPP1_MDP_RDMA MTK_M4U_ID(SMI_L5_ID, 0) +#define M4U_PORT_L5_SVPP1_MDP_FG MTK_M4U_ID(SMI_L5_ID, 1) +#define M4U_PORT_L5_SVPP1_MDP_OVL MTK_M4U_ID(SMI_L5_ID, 2) +#define M4U_PORT_L5_SVPP1_MDP_WROT MTK_M4U_ID(SMI_L5_ID, 3) +#define M4U_PORT_L5_SVPP2_MDP_RDMA MTK_M4U_ID(SMI_L5_ID, 4) +#define M4U_PORT_L5_SVPP2_MDP_FG MTK_M4U_ID(SMI_L5_ID, 5) +#define M4U_PORT_L5_SVPP2_MDP_WROT MTK_M4U_ID(SMI_L5_ID, 6) +#define M4U_PORT_L5_LARB5_FAKE_ENG MTK_M4U_ID(SMI_L5_ID, 7) + +/* LARB 6 -- VPP-1 */ +#define M4U_PORT_L6_SVPP3_MDP_RDMA MTK_M4U_ID(SMI_L6_ID, 0) +#define M4U_PORT_L6_SVPP3_MDP_FG MTK_M4U_ID(SMI_L6_ID, 1) +#define M4U_PORT_L6_SVPP3_MDP_WROT MTK_M4U_ID(SMI_L6_ID, 2) +#define M4U_PORT_L6_LARB6_FAKE_ENG MTK_M4U_ID(SMI_L6_ID, 3) + +/* LARB 7 -- WPE */ +#define M4U_PORT_L7_WPE_RDMA_0 MTK_M4U_ID(SMI_L7_ID, 0) +#define M4U_PORT_L7_WPE_RDMA_1 MTK_M4U_ID(SMI_L7_ID, 1) +#define M4U_PORT_L7_WPE_WDMA_0 MTK_M4U_ID(SMI_L7_ID, 2) + +/* LARB 9 -- IMG-M */ +#define M4U_PORT_L9_IMGI_T1_A MTK_M4U_ID(SMI_L9_ID, 0) +#define M4U_PORT_L9_UFDI_T1_A MTK_M4U_ID(SMI_L9_ID, 1) +#define M4U_PORT_L9_IMGBI_T1_A MTK_M4U_ID(SMI_L9_ID, 2) +#define M4U_PORT_L9_IMGCI_T1_A MTK_M4U_ID(SMI_L9_ID, 3) +#define M4U_PORT_L9_SMTI_T1_A MTK_M4U_ID(SMI_L9_ID, 4) +#define M4U_PORT_L9_SMTI_T4_A MTK_M4U_ID(SMI_L9_ID, 5) +#define M4U_PORT_L9_TNCSTI_T1_A MTK_M4U_ID(SMI_L9_ID, 6) +#define M4U_PORT_L9_TNCSTI_T4_A MTK_M4U_ID(SMI_L9_ID, 7) +#define M4U_PORT_L9_YUVO_T1_A MTK_M4U_ID(SMI_L9_ID, 8) +#define M4U_PORT_L9_YUVBO_T1_A MTK_M4U_ID(SMI_L9_ID, 9) +#define M4U_PORT_L9_YUVCO_T1_A MTK_M4U_ID(SMI_L9_ID, 10) +#define M4U_PORT_L9_TIMGO_T1_A MTK_M4U_ID(SMI_L9_ID, 11) +#define M4U_PORT_L9_YUVO_T2_A MTK_M4U_ID(SMI_L9_ID, 12) +#define M4U_PORT_L9_YUVO_T5_A MTK_M4U_ID(SMI_L9_ID, 13) +#define M4U_PORT_L9_IMGI_T1_B MTK_M4U_ID(SMI_L9_ID, 14) +#define M4U_PORT_L9_IMGBI_T1_B MTK_M4U_ID(SMI_L9_ID, 15) +#define M4U_PORT_L9_IMGCI_T1_B MTK_M4U_ID(SMI_L9_ID, 16) +#define M4U_PORT_L9_SMTI_T4_B MTK_M4U_ID(SMI_L9_ID, 17) +#define M4U_PORT_L9_TNCSO_T1_A MTK_M4U_ID(SMI_L9_ID, 18) +#define M4U_PORT_L9_SMTO_T1_A MTK_M4U_ID(SMI_L9_ID, 19) +#define M4U_PORT_L9_SMTO_T4_A MTK_M4U_ID(SMI_L9_ID, 20) +#define M4U_PORT_L9_TNCSTO_T1_A MTK_M4U_ID(SMI_L9_ID, 21) +#define M4U_PORT_L9_YUVO_T2_B MTK_M4U_ID(SMI_L9_ID, 22) +#define M4U_PORT_L9_YUVO_T5_B MTK_M4U_ID(SMI_L9_ID, 23) +#define M4U_PORT_L9_SMTO_T4_B MTK_M4U_ID(SMI_L9_ID, 24) + +/* LARB 10 -- IMG-D */ +#define M4U_PORT_L10_IMGI_D1 MTK_M4U_ID(SMI_L10_ID, 0) +#define M4U_PORT_L10_IMGBI_D1 MTK_M4U_ID(SMI_L10_ID, 1) +#define M4U_PORT_L10_IMGCI_D1 MTK_M4U_ID(SMI_L10_ID, 2) +#define M4U_PORT_L10_IMGDI_D1 MTK_M4U_ID(SMI_L10_ID, 3) +#define M4U_PORT_L10_DEPI_D1 MTK_M4U_ID(SMI_L10_ID, 4) +#define M4U_PORT_L10_DMGI_D1 MTK_M4U_ID(SMI_L10_ID, 5) +#define M4U_PORT_L10_SMTI_D1 MTK_M4U_ID(SMI_L10_ID, 6) +#define M4U_PORT_L10_RECI_D1 MTK_M4U_ID(SMI_L10_ID, 7) +#define M4U_PORT_L10_RECI_D1_N MTK_M4U_ID(SMI_L10_ID, 8) +#define M4U_PORT_L10_TNRWI_D1 MTK_M4U_ID(SMI_L10_ID, 9) +#define M4U_PORT_L10_TNRCI_D1 MTK_M4U_ID(SMI_L10_ID, 10) +#define M4U_PORT_L10_TNRCI_D1_N MTK_M4U_ID(SMI_L10_ID, 11) +#define M4U_PORT_L10_IMG4O_D1 MTK_M4U_ID(SMI_L10_ID, 12) +#define M4U_PORT_L10_IMG4BO_D1 MTK_M4U_ID(SMI_L10_ID, 13) +#define M4U_PORT_L10_SMTI_D8 MTK_M4U_ID(SMI_L10_ID, 14) +#define M4U_PORT_L10_SMTO_D1 MTK_M4U_ID(SMI_L10_ID, 15) +#define M4U_PORT_L10_TNRMO_D1 MTK_M4U_ID(SMI_L10_ID, 16) +#define M4U_PORT_L10_TNRMO_D1_N MTK_M4U_ID(SMI_L10_ID, 17) +#define M4U_PORT_L10_SMTO_D8 MTK_M4U_ID(SMI_L10_ID, 18) +#define M4U_PORT_L10_DBGO_D1 MTK_M4U_ID(SMI_L10_ID, 19) + +/* LARB 11A -- IMG-D */ +#define M4U_PORT_L11A_WPE_RDMA_0 MTK_M4U_ID(SMI_L11A_ID, 0) +#define M4U_PORT_L11A_WPE_RDMA_1 MTK_M4U_ID(SMI_L11A_ID, 1) +#define M4U_PORT_L11A_WPE_RDMA_4P_0 MTK_M4U_ID(SMI_L11A_ID, 2) +#define M4U_PORT_L11A_WPE_RDMA_4P_1 MTK_M4U_ID(SMI_L11A_ID, 3) +#define M4U_PORT_L11A_WPE_CQ0 MTK_M4U_ID(SMI_L11A_ID, 4) +#define M4U_PORT_L11A_WPE_CQ1 MTK_M4U_ID(SMI_L11A_ID, 5) +#define M4U_PORT_L11A_PIMGI_P1 MTK_M4U_ID(SMI_L11A_ID, 6) +#define M4U_PORT_L11A_PIMGBI_P1 MTK_M4U_ID(SMI_L11A_ID, 7) +#define M4U_PORT_L11A_PIMGCI_P1 MTK_M4U_ID(SMI_L11A_ID, 8) +#define M4U_PORT_L11A_IMGI_T1_C MTK_M4U_ID(SMI_L11A_ID, 9) +#define M4U_PORT_L11A_IMGBI_T1_C MTK_M4U_ID(SMI_L11A_ID, 10) +#define M4U_PORT_L11A_IMGCI_T1_C MTK_M4U_ID(SMI_L11A_ID, 11) +#define M4U_PORT_L11A_SMTI_T1_C MTK_M4U_ID(SMI_L11A_ID, 12) +#define M4U_PORT_L11A_SMTI_T4_C MTK_M4U_ID(SMI_L11A_ID, 13) +#define M4U_PORT_L11A_SMTI_T6_C MTK_M4U_ID(SMI_L11A_ID, 14) +#define M4U_PORT_L11A_YUVO_T1_C MTK_M4U_ID(SMI_L11A_ID, 15) +#define M4U_PORT_L11A_YUVBO_T1_C MTK_M4U_ID(SMI_L11A_ID, 16) +#define M4U_PORT_L11A_YUVCO_T1_C MTK_M4U_ID(SMI_L11A_ID, 17) +#define M4U_PORT_L11A_WPE_WDMA_0 MTK_M4U_ID(SMI_L11A_ID, 18) +#define M4U_PORT_L11A_WPE_WDMA_4P_0 MTK_M4U_ID(SMI_L11A_ID, 19) +#define M4U_PORT_L11A_WROT_P1 MTK_M4U_ID(SMI_L11A_ID, 20) +#define M4U_PORT_L11A_TCCSO_P1 MTK_M4U_ID(SMI_L11A_ID, 21) +#define M4U_PORT_L11A_TCCSI_P1 MTK_M4U_ID(SMI_L11A_ID, 22) +#define M4U_PORT_L11A_TIMGO_T1_C MTK_M4U_ID(SMI_L11A_ID, 23) +#define M4U_PORT_L11A_YUVO_T2_C MTK_M4U_ID(SMI_L11A_ID, 24) +#define M4U_PORT_L11A_YUVO_T5_C MTK_M4U_ID(SMI_L11A_ID, 25) +#define M4U_PORT_L11A_SMTO_T1_C MTK_M4U_ID(SMI_L11A_ID, 26) +#define M4U_PORT_L11A_SMTO_T4_C MTK_M4U_ID(SMI_L11A_ID, 27) +#define M4U_PORT_L11A_SMTO_T6_C MTK_M4U_ID(SMI_L11A_ID, 28) +#define M4U_PORT_L11A_DBGO_T1_C MTK_M4U_ID(SMI_L11A_ID, 29) + +/* LARB 11B -- IMG-D */ +#define M4U_PORT_L11B_WPE_RDMA_0 MTK_M4U_ID(SMI_L11B_ID, 0) +#define M4U_PORT_L11B_WPE_RDMA_1 MTK_M4U_ID(SMI_L11B_ID, 1) +#define M4U_PORT_L11B_WPE_RDMA_4P_0 MTK_M4U_ID(SMI_L11B_ID, 2) +#define M4U_PORT_L11B_WPE_RDMA_4P_1 MTK_M4U_ID(SMI_L11B_ID, 3) +#define M4U_PORT_L11B_WPE_CQ0 MTK_M4U_ID(SMI_L11B_ID, 4) +#define M4U_PORT_L11B_WPE_CQ1 MTK_M4U_ID(SMI_L11B_ID, 5) +#define M4U_PORT_L11B_PIMGI_P1 MTK_M4U_ID(SMI_L11B_ID, 6) +#define M4U_PORT_L11B_PIMGBI_P1 MTK_M4U_ID(SMI_L11B_ID, 7) +#define M4U_PORT_L11B_PIMGCI_P1 MTK_M4U_ID(SMI_L11B_ID, 8) +#define M4U_PORT_L11B_IMGI_T1_C MTK_M4U_ID(SMI_L11B_ID, 9) +#define M4U_PORT_L11B_IMGBI_T1_C MTK_M4U_ID(SMI_L11B_ID, 10) +#define M4U_PORT_L11B_IMGCI_T1_C MTK_M4U_ID(SMI_L11B_ID, 11) +#define M4U_PORT_L11B_SMTI_T1_C MTK_M4U_ID(SMI_L11B_ID, 12) +#define M4U_PORT_L11B_SMTI_T4_C MTK_M4U_ID(SMI_L11B_ID, 13) +#define M4U_PORT_L11B_SMTI_T6_C MTK_M4U_ID(SMI_L11B_ID, 14) +#define M4U_PORT_L11B_YUVO_T1_C MTK_M4U_ID(SMI_L11B_ID, 15) +#define M4U_PORT_L11B_YUVBO_T1_C MTK_M4U_ID(SMI_L11B_ID, 16) +#define M4U_PORT_L11B_YUVCO_T1_C MTK_M4U_ID(SMI_L11B_ID, 17) +#define M4U_PORT_L11B_WPE_WDMA_0 MTK_M4U_ID(SMI_L11B_ID, 18) +#define M4U_PORT_L11B_WPE_WDMA_4P_0 MTK_M4U_ID(SMI_L11B_ID, 19) +#define M4U_PORT_L11B_WROT_P1 MTK_M4U_ID(SMI_L11B_ID, 20) +#define M4U_PORT_L11B_TCCSO_P1 MTK_M4U_ID(SMI_L11B_ID, 21) +#define M4U_PORT_L11B_TCCSI_P1 MTK_M4U_ID(SMI_L11B_ID, 22) +#define M4U_PORT_L11B_TIMGO_T1_C MTK_M4U_ID(SMI_L11B_ID, 23) +#define M4U_PORT_L11B_YUVO_T2_C MTK_M4U_ID(SMI_L11B_ID, 24) +#define M4U_PORT_L11B_YUVO_T5_C MTK_M4U_ID(SMI_L11B_ID, 25) +#define M4U_PORT_L11B_SMTO_T1_C MTK_M4U_ID(SMI_L11B_ID, 26) +#define M4U_PORT_L11B_SMTO_T4_C MTK_M4U_ID(SMI_L11B_ID, 27) +#define M4U_PORT_L11B_SMTO_T6_C MTK_M4U_ID(SMI_L11B_ID, 28) +#define M4U_PORT_L11B_DBGO_T1_C MTK_M4U_ID(SMI_L11B_ID, 29) + +/* LARB 11C -- IMG-D */ +#define M4U_PORT_L11C_WPE_RDMA_0 MTK_M4U_ID(SMI_L11C_ID, 0) +#define M4U_PORT_L11C_WPE_RDMA_1 MTK_M4U_ID(SMI_L11C_ID, 1) +#define M4U_PORT_L11C_WPE_RDMA_4P_0 MTK_M4U_ID(SMI_L11C_ID, 2) +#define M4U_PORT_L11C_WPE_RDMA_4P_1 MTK_M4U_ID(SMI_L11C_ID, 3) +#define M4U_PORT_L11C_WPE_CQ0 MTK_M4U_ID(SMI_L11C_ID, 4) +#define M4U_PORT_L11C_WPE_CQ1 MTK_M4U_ID(SMI_L11C_ID, 5) +#define M4U_PORT_L11C_PIMGI_P1 MTK_M4U_ID(SMI_L11C_ID, 6) +#define M4U_PORT_L11C_PIMGBI_P1 MTK_M4U_ID(SMI_L11C_ID, 7) +#define M4U_PORT_L11C_PIMGCI_P1 MTK_M4U_ID(SMI_L11C_ID, 8) +#define M4U_PORT_L11C_IMGI_T1_C MTK_M4U_ID(SMI_L11C_ID, 9) +#define M4U_PORT_L11C_IMGBI_T1_C MTK_M4U_ID(SMI_L11C_ID, 10) +#define M4U_PORT_L11C_IMGCI_T1_C MTK_M4U_ID(SMI_L11C_ID, 11) +#define M4U_PORT_L11C_SMTI_T1_C MTK_M4U_ID(SMI_L11C_ID, 12) +#define M4U_PORT_L11C_SMTI_T4_C MTK_M4U_ID(SMI_L11C_ID, 13) +#define M4U_PORT_L11C_SMTI_T6_C MTK_M4U_ID(SMI_L11C_ID, 14) +#define M4U_PORT_L11C_YUVO_T1_C MTK_M4U_ID(SMI_L11C_ID, 15) +#define M4U_PORT_L11C_YUVBO_T1_C MTK_M4U_ID(SMI_L11C_ID, 16) +#define M4U_PORT_L11C_YUVCO_T1_C MTK_M4U_ID(SMI_L11C_ID, 17) +#define M4U_PORT_L11C_WPE_WDMA_0 MTK_M4U_ID(SMI_L11C_ID, 18) +#define M4U_PORT_L11C_WPE_WDMA_4P_0 MTK_M4U_ID(SMI_L11C_ID, 19) +#define M4U_PORT_L11C_WROT_P1 MTK_M4U_ID(SMI_L11C_ID, 20) +#define M4U_PORT_L11C_TCCSO_P1 MTK_M4U_ID(SMI_L11C_ID, 21) +#define M4U_PORT_L11C_TCCSI_P1 MTK_M4U_ID(SMI_L11C_ID, 22) +#define M4U_PORT_L11C_TIMGO_T1_C MTK_M4U_ID(SMI_L11C_ID, 23) +#define M4U_PORT_L11C_YUVO_T2_C MTK_M4U_ID(SMI_L11C_ID, 24) +#define M4U_PORT_L11C_YUVO_T5_C MTK_M4U_ID(SMI_L11C_ID, 25) +#define M4U_PORT_L11C_SMTO_T1_C MTK_M4U_ID(SMI_L11C_ID, 26) +#define M4U_PORT_L11C_SMTO_T4_C MTK_M4U_ID(SMI_L11C_ID, 27) +#define M4U_PORT_L11C_SMTO_T6_C MTK_M4U_ID(SMI_L11C_ID, 28) +#define M4U_PORT_L11C_DBGO_T1_C MTK_M4U_ID(SMI_L11C_ID, 29) + +/* LARB 12 -- IPE */ +#define M4U_PORT_L12_FDVT_RDA_0 MTK_M4U_ID(SMI_L12_ID, 0) +#define M4U_PORT_L12_FDVT_RDB_0 MTK_M4U_ID(SMI_L12_ID, 1) +#define M4U_PORT_L12_FDVT_WRA_0 MTK_M4U_ID(SMI_L12_ID, 2) +#define M4U_PORT_L12_FDVT_WRB_0 MTK_M4U_ID(SMI_L12_ID, 3) +#define M4U_PORT_L12_ME_RDMA MTK_M4U_ID(SMI_L12_ID, 4) +#define M4U_PORT_L12_ME_WDMA MTK_M4U_ID(SMI_L12_ID, 5) +#define M4U_PORT_L12_DVS_RDMA MTK_M4U_ID(SMI_L12_ID, 6) +#define M4U_PORT_L12_DVS_WDMA MTK_M4U_ID(SMI_L12_ID, 7) +#define M4U_PORT_L12_DVP_RDMA MTK_M4U_ID(SMI_L12_ID, 8) +#define M4U_PORT_L12_DVP_WDMA MTK_M4U_ID(SMI_L12_ID, 9) +#define M4U_PORT_L12_FDVT_2ND_RDA_0 MTK_M4U_ID(SMI_L12_ID, 10) +#define M4U_PORT_L12_FDVT_2ND_RDB_0 MTK_M4U_ID(SMI_L12_ID, 11) +#define M4U_PORT_L12_FDVT_2ND_WRA_0 MTK_M4U_ID(SMI_L12_ID, 12) +#define M4U_PORT_L12_FDVT_2ND_WRB_0 MTK_M4U_ID(SMI_L12_ID, 13) +#define M4U_PORT_L12_DHZEI_E1 MTK_M4U_ID(SMI_L12_ID, 14) +#define M4U_PORT_L12_DHZEO_E1 MTK_M4U_ID(SMI_L12_ID, 15) + +/* LARB 13 -- CAM-1 */ +#define M4U_PORT_L13_CAMSV_CQI_E1 MTK_M4U_ID(SMI_L13_ID, 0) +#define M4U_PORT_L13_CAMSV_CQI_E2 MTK_M4U_ID(SMI_L13_ID, 1) +#define M4U_PORT_L13_GCAMSV_A_IMGO_1 MTK_M4U_ID(SMI_L13_ID, 2) +#define M4U_PORT_L13_GCAMSV_C_IMGO_1 MTK_M4U_ID(SMI_L13_ID, 3) +#define M4U_PORT_L13_GCAMSV_A_IMGO_2 MTK_M4U_ID(SMI_L13_ID, 4) +#define M4U_PORT_L13_GCAMSV_C_IMGO_2 MTK_M4U_ID(SMI_L13_ID, 5) +#define M4U_PORT_L13_PDAI_A_0 MTK_M4U_ID(SMI_L13_ID, 6) +#define M4U_PORT_L13_PDAI_A_1 MTK_M4U_ID(SMI_L13_ID, 7) +#define M4U_PORT_L13_CAMSV_CQI_B_E1 MTK_M4U_ID(SMI_L13_ID, 8) +#define M4U_PORT_L13_CAMSV_CQI_B_E2 MTK_M4U_ID(SMI_L13_ID, 9) +#define M4U_PORT_L13_CAMSV_CQI_C_E1 MTK_M4U_ID(SMI_L13_ID, 10) +#define M4U_PORT_L13_CAMSV_CQI_C_E2 MTK_M4U_ID(SMI_L13_ID, 11) +#define M4U_PORT_L13_GCAMSV_E_IMGO_1 MTK_M4U_ID(SMI_L13_ID, 12) +#define M4U_PORT_L13_GCAMSV_E_IMGO_2 MTK_M4U_ID(SMI_L13_ID, 13) +#define M4U_PORT_L13_GCAMSV_A_UFEO_1 MTK_M4U_ID(SMI_L13_ID, 14) +#define M4U_PORT_L13_GCAMSV_C_UFEO_1 MTK_M4U_ID(SMI_L13_ID, 15) +#define M4U_PORT_L13_GCAMSV_A_UFEO_2 MTK_M4U_ID(SMI_L13_ID, 16) +#define M4U_PORT_L13_GCAMSV_C_UFEO_2 MTK_M4U_ID(SMI_L13_ID, 17) +#define M4U_PORT_L13_GCAMSV_E_UFEO_1 MTK_M4U_ID(SMI_L13_ID, 18) +#define M4U_PORT_L13_GCAMSV_E_UFEO_2 MTK_M4U_ID(SMI_L13_ID, 19) +#define M4U_PORT_L13_GCAMSV_G_IMGO_1 MTK_M4U_ID(SMI_L13_ID, 20) +#define M4U_PORT_L13_GCAMSV_G_IMGO_2 MTK_M4U_ID(SMI_L13_ID, 21) +#define M4U_PORT_L13_PDAO_A MTK_M4U_ID(SMI_L13_ID, 22) +#define M4U_PORT_L13_PDAO_C MTK_M4U_ID(SMI_L13_ID, 23) + +/* LARB 14 -- CAM-1 */ +#define M4U_PORT_L14_GCAMSV_B_IMGO_1 MTK_M4U_ID(SMI_L14_ID, 0) +#define M4U_PORT_L14_GCAMSV_B_IMGO_2 MTK_M4U_ID(SMI_L14_ID, 1) +#define M4U_PORT_L14_SCAMSV_A_IMGO_1 MTK_M4U_ID(SMI_L14_ID, 2) +#define M4U_PORT_L14_SCAMSV_A_IMGO_2 MTK_M4U_ID(SMI_L14_ID, 3) +#define M4U_PORT_L14_SCAMSV_B_IMGO_1 MTK_M4U_ID(SMI_L14_ID, 4) +#define M4U_PORT_L14_SCAMSV_B_IMGO_2 MTK_M4U_ID(SMI_L14_ID, 5) +#define M4U_PORT_L14_PDAI_B_0 MTK_M4U_ID(SMI_L14_ID, 6) +#define M4U_PORT_L14_PDAI_B_1 MTK_M4U_ID(SMI_L14_ID, 7) +#define M4U_PORT_L14_GCAMSV_D_IMGO_1 MTK_M4U_ID(SMI_L14_ID, 8) +#define M4U_PORT_L14_GCAMSV_D_IMGO_2 MTK_M4U_ID(SMI_L14_ID, 9) +#define M4U_PORT_L14_GCAMSV_F_IMGO_1 MTK_M4U_ID(SMI_L14_ID, 10) +#define M4U_PORT_L14_GCAMSV_F_IMGO_2 MTK_M4U_ID(SMI_L14_ID, 11) +#define M4U_PORT_L14_GCAMSV_H_IMGO_1 MTK_M4U_ID(SMI_L14_ID, 12) +#define M4U_PORT_L14_GCAMSV_H_IMGO_2 MTK_M4U_ID(SMI_L14_ID, 13) +#define M4U_PORT_L14_GCAMSV_B_UFEO_1 MTK_M4U_ID(SMI_L14_ID, 14) +#define M4U_PORT_L14_GCAMSV_B_UFEO_2 MTK_M4U_ID(SMI_L14_ID, 15) +#define M4U_PORT_L14_GCAMSV_D_UFEO_1 MTK_M4U_ID(SMI_L14_ID, 16) +#define M4U_PORT_L14_GCAMSV_D_UFEO_2 MTK_M4U_ID(SMI_L14_ID, 17) +#define M4U_PORT_L14_PDAO_B MTK_M4U_ID(SMI_L14_ID, 18) +#define M4U_PORT_L14_IPUI MTK_M4U_ID(SMI_L14_ID, 19) +#define M4U_PORT_L14_IPUO MTK_M4U_ID(SMI_L14_ID, 20) +#define M4U_PORT_L14_IPU3O MTK_M4U_ID(SMI_L14_ID, 21) +#define M4U_PORT_L14_FAKE MTK_M4U_ID(SMI_L14_ID, 22) + +/* LARB 15 -- IMG-D */ +#define M4U_PORT_L15_VIPI_D1 MTK_M4U_ID(SMI_L15_ID, 0) +#define M4U_PORT_L15_VIPBI_D1 MTK_M4U_ID(SMI_L15_ID, 1) +#define M4U_PORT_L15_SMTI_D6 MTK_M4U_ID(SMI_L15_ID, 2) +#define M4U_PORT_L15_TNCSTI_D1 MTK_M4U_ID(SMI_L15_ID, 3) +#define M4U_PORT_L15_TNCSTI_D4 MTK_M4U_ID(SMI_L15_ID, 4) +#define M4U_PORT_L15_SMTI_D4 MTK_M4U_ID(SMI_L15_ID, 5) +#define M4U_PORT_L15_IMG3O_D1 MTK_M4U_ID(SMI_L15_ID, 6) +#define M4U_PORT_L15_IMG3BO_D1 MTK_M4U_ID(SMI_L15_ID, 7) +#define M4U_PORT_L15_IMG3CO_D1 MTK_M4U_ID(SMI_L15_ID, 8) +#define M4U_PORT_L15_IMG2O_D1 MTK_M4U_ID(SMI_L15_ID, 9) +#define M4U_PORT_L15_SMTI_D9 MTK_M4U_ID(SMI_L15_ID, 10) +#define M4U_PORT_L15_SMTO_D4 MTK_M4U_ID(SMI_L15_ID, 11) +#define M4U_PORT_L15_FEO_D1 MTK_M4U_ID(SMI_L15_ID, 12) +#define M4U_PORT_L15_TNCSO_D1 MTK_M4U_ID(SMI_L15_ID, 13) +#define M4U_PORT_L15_TNCSTO_D1 MTK_M4U_ID(SMI_L15_ID, 14) +#define M4U_PORT_L15_SMTO_D6 MTK_M4U_ID(SMI_L15_ID, 15) +#define M4U_PORT_L15_SMTO_D9 MTK_M4U_ID(SMI_L15_ID, 16) +#define M4U_PORT_L15_TNCO_D1 MTK_M4U_ID(SMI_L15_ID, 17) +#define M4U_PORT_L15_TNCO_D1_N MTK_M4U_ID(SMI_L15_ID, 18) + +/* LARB 16A -- CAM */ +#define M4U_PORT_L16A_IMGO_R1 MTK_M4U_ID(SMI_L16A_ID, 0) +#define M4U_PORT_L16A_CQI_R1 MTK_M4U_ID(SMI_L16A_ID, 1) +#define M4U_PORT_L16A_CQI_R2 MTK_M4U_ID(SMI_L16A_ID, 2) +#define M4U_PORT_L16A_BPCI_R1 MTK_M4U_ID(SMI_L16A_ID, 3) +#define M4U_PORT_L16A_LSCI_R1 MTK_M4U_ID(SMI_L16A_ID, 4) +#define M4U_PORT_L16A_RAWI_R2 MTK_M4U_ID(SMI_L16A_ID, 5) +#define M4U_PORT_L16A_RAWI_R3 MTK_M4U_ID(SMI_L16A_ID, 6) +#define M4U_PORT_L16A_UFDI_R2 MTK_M4U_ID(SMI_L16A_ID, 7) +#define M4U_PORT_L16A_UFDI_R3 MTK_M4U_ID(SMI_L16A_ID, 8) +#define M4U_PORT_L16A_RAWI_R4 MTK_M4U_ID(SMI_L16A_ID, 9) +#define M4U_PORT_L16A_RAWI_R5 MTK_M4U_ID(SMI_L16A_ID, 10) +#define M4U_PORT_L16A_AAI_R1 MTK_M4U_ID(SMI_L16A_ID, 11) +#define M4U_PORT_L16A_UFDI_R5 MTK_M4U_ID(SMI_L16A_ID, 12) +#define M4U_PORT_L16A_FHO_R1 MTK_M4U_ID(SMI_L16A_ID, 13) +#define M4U_PORT_L16A_AAO_R1 MTK_M4U_ID(SMI_L16A_ID, 14) +#define M4U_PORT_L16A_TSFSO_R1 MTK_M4U_ID(SMI_L16A_ID, 15) +#define M4U_PORT_L16A_FLKO_R1 MTK_M4U_ID(SMI_L16A_ID, 16) + +/* LARB 16B -- CAM */ +#define M4U_PORT_L16B_IMGO_R1 MTK_M4U_ID(SMI_L16B_ID, 0) +#define M4U_PORT_L16B_CQI_R1 MTK_M4U_ID(SMI_L16B_ID, 1) +#define M4U_PORT_L16B_CQI_R2 MTK_M4U_ID(SMI_L16B_ID, 2) +#define M4U_PORT_L16B_BPCI_R1 MTK_M4U_ID(SMI_L16B_ID, 3) +#define M4U_PORT_L16B_LSCI_R1 MTK_M4U_ID(SMI_L16B_ID, 4) +#define M4U_PORT_L16B_RAWI_R2 MTK_M4U_ID(SMI_L16B_ID, 5) +#define M4U_PORT_L16B_RAWI_R3 MTK_M4U_ID(SMI_L16B_ID, 6) +#define M4U_PORT_L16B_UFDI_R2 MTK_M4U_ID(SMI_L16B_ID, 7) +#define M4U_PORT_L16B_UFDI_R3 MTK_M4U_ID(SMI_L16B_ID, 8) +#define M4U_PORT_L16B_RAWI_R4 MTK_M4U_ID(SMI_L16B_ID, 9) +#define M4U_PORT_L16B_RAWI_R5 MTK_M4U_ID(SMI_L16B_ID, 10) +#define M4U_PORT_L16B_AAI_R1 MTK_M4U_ID(SMI_L16B_ID, 11) +#define M4U_PORT_L16B_UFDI_R5 MTK_M4U_ID(SMI_L16B_ID, 12) +#define M4U_PORT_L16B_FHO_R1 MTK_M4U_ID(SMI_L16B_ID, 13) +#define M4U_PORT_L16B_AAO_R1 MTK_M4U_ID(SMI_L16B_ID, 14) +#define M4U_PORT_L16B_TSFSO_R1 MTK_M4U_ID(SMI_L16B_ID, 15) +#define M4U_PORT_L16B_FLKO_R1 MTK_M4U_ID(SMI_L16B_ID, 16) + +/* LARB 17A -- CAM */ +#define M4U_PORT_L17A_YUVO_R1 MTK_M4U_ID(SMI_L17A_ID, 0) +#define M4U_PORT_L17A_YUVO_R3 MTK_M4U_ID(SMI_L17A_ID, 1) +#define M4U_PORT_L17A_YUVCO_R1 MTK_M4U_ID(SMI_L17A_ID, 2) +#define M4U_PORT_L17A_YUVO_R2 MTK_M4U_ID(SMI_L17A_ID, 3) +#define M4U_PORT_L17A_RZH1N2TO_R1 MTK_M4U_ID(SMI_L17A_ID, 4) +#define M4U_PORT_L17A_DRZS4NO_R1 MTK_M4U_ID(SMI_L17A_ID, 5) +#define M4U_PORT_L17A_TNCSO_R1 MTK_M4U_ID(SMI_L17A_ID, 6) + +/* LARB 17B -- CAM */ +#define M4U_PORT_L17B_YUVO_R1 MTK_M4U_ID(SMI_L17B_ID, 0) +#define M4U_PORT_L17B_YUVO_R3 MTK_M4U_ID(SMI_L17B_ID, 1) +#define M4U_PORT_L17B_YUVCO_R1 MTK_M4U_ID(SMI_L17B_ID, 2) +#define M4U_PORT_L17B_YUVO_R2 MTK_M4U_ID(SMI_L17B_ID, 3) +#define M4U_PORT_L17B_RZH1N2TO_R1 MTK_M4U_ID(SMI_L17B_ID, 4) +#define M4U_PORT_L17B_DRZS4NO_R1 MTK_M4U_ID(SMI_L17B_ID, 5) +#define M4U_PORT_L17B_TNCSO_R1 MTK_M4U_ID(SMI_L17B_ID, 6) + +/* LARB 19 -- VENC */ +#define M4U_PORT_L19_VENC_RCPU MTK_M4U_ID(SMI_L19_ID, 0) +#define M4U_PORT_L19_VENC_REC MTK_M4U_ID(SMI_L19_ID, 1) +#define M4U_PORT_L19_VENC_BSDMA MTK_M4U_ID(SMI_L19_ID, 2) +#define M4U_PORT_L19_VENC_SV_COMV MTK_M4U_ID(SMI_L19_ID, 3) +#define M4U_PORT_L19_VENC_RD_COMV MTK_M4U_ID(SMI_L19_ID, 4) +#define M4U_PORT_L19_VENC_NBM_RDMA MTK_M4U_ID(SMI_L19_ID, 5) +#define M4U_PORT_L19_VENC_NBM_RDMA_LITE MTK_M4U_ID(SMI_L19_ID, 6) +#define M4U_PORT_L19_JPGENC_Y_RDMA MTK_M4U_ID(SMI_L19_ID, 7) +#define M4U_PORT_L19_JPGENC_C_RDMA MTK_M4U_ID(SMI_L19_ID, 8) +#define M4U_PORT_L19_JPGENC_Q_TABLE MTK_M4U_ID(SMI_L19_ID, 9) +#define M4U_PORT_L19_VENC_SUB_W_LUMA MTK_M4U_ID(SMI_L19_ID, 10) +#define M4U_PORT_L19_VENC_FCS_NBM_RDMA MTK_M4U_ID(SMI_L19_ID, 11) +#define M4U_PORT_L19_JPGENC_BSDMA MTK_M4U_ID(SMI_L19_ID, 12) +#define M4U_PORT_L19_JPGDEC_WDMA_0 MTK_M4U_ID(SMI_L19_ID, 13) +#define M4U_PORT_L19_JPGDEC_BSDMA_0 MTK_M4U_ID(SMI_L19_ID, 14) +#define M4U_PORT_L19_VENC_NBM_WDMA MTK_M4U_ID(SMI_L19_ID, 15) +#define M4U_PORT_L19_VENC_NBM_WDMA_LITE MTK_M4U_ID(SMI_L19_ID, 16) +#define M4U_PORT_L19_VENC_FCS_NBM_WDMA MTK_M4U_ID(SMI_L19_ID, 17) +#define M4U_PORT_L19_JPGDEC_WDMA_1 MTK_M4U_ID(SMI_L19_ID, 18) +#define M4U_PORT_L19_JPGDEC_BSDMA_1 MTK_M4U_ID(SMI_L19_ID, 19) +#define M4U_PORT_L19_JPGDEC_HUFF_OFFSET_1 MTK_M4U_ID(SMI_L19_ID, 20) +#define M4U_PORT_L19_JPGDEC_HUFF_OFFSET_0 MTK_M4U_ID(SMI_L19_ID, 21) +#define M4U_PORT_L19_VENC_CUR_LUMA MTK_M4U_ID(SMI_L19_ID, 22) +#define M4U_PORT_L19_VENC_CUR_CHROMA MTK_M4U_ID(SMI_L19_ID, 23) +#define M4U_PORT_L19_VENC_REF_LUMA MTK_M4U_ID(SMI_L19_ID, 24) +#define M4U_PORT_L19_VENC_REF_CHROMA MTK_M4U_ID(SMI_L19_ID, 25) +#define M4U_PORT_L19_VENC_SUB_R_LUMA MTK_M4U_ID(SMI_L19_ID, 26) + +/* LARB 21 -- VDEC-CORE0 */ +#define M4U_PORT_L21_HW_VDEC_MC_EXT MTK_M4U_ID(SMI_L21_ID, 0) +#define M4U_PORT_L21_HW_VDEC_UFO_EXT MTK_M4U_ID(SMI_L21_ID, 1) +#define M4U_PORT_L21_HW_VDEC_PP_EXT MTK_M4U_ID(SMI_L21_ID, 2) +#define M4U_PORT_L21_HW_VDEC_PRED_RD_EXT MTK_M4U_ID(SMI_L21_ID, 3) +#define M4U_PORT_L21_HW_VDEC_PRED_WR_EXT MTK_M4U_ID(SMI_L21_ID, 4) +#define M4U_PORT_L21_HW_VDEC_PPWRAP_EXT MTK_M4U_ID(SMI_L21_ID, 5) +#define M4U_PORT_L21_HW_VDEC_TILE_EXT MTK_M4U_ID(SMI_L21_ID, 6) +#define M4U_PORT_L21_HW_VDEC_VLD_EXT MTK_M4U_ID(SMI_L21_ID, 7) +#define M4U_PORT_L21_HW_VDEC_VLD2_EXT MTK_M4U_ID(SMI_L21_ID, 8) +#define M4U_PORT_L21_HW_VDEC_AVC_MV_EXT MTK_M4U_ID(SMI_L21_ID, 9) +#define M4U_PORT_L21_HW_VDEC_UFO_EXT_C MTK_M4U_ID(SMI_L21_ID, 10) + +/* LARB 23 -- VDEC-SOC */ +#define M4U_PORT_L23_HW_VDEC_LAT0_VLD_EXT MTK_M4U_ID(SMI_L23_ID, 0) +#define M4U_PORT_L23_HW_VDEC_LAT0_VLD2_EXT MTK_M4U_ID(SMI_L23_ID, 1) +#define M4U_PORT_L23_HW_VDEC_LAT0_AVC_MV_EXT MTK_M4U_ID(SMI_L23_ID, 2) +#define M4U_PORT_L23_HW_VDEC_LAT0_PRED_RD_EXT MTK_M4U_ID(SMI_L23_ID, 3) +#define M4U_PORT_L23_HW_VDEC_LAT0_TILE_EXT MTK_M4U_ID(SMI_L23_ID, 4) +#define M4U_PORT_L23_HW_VDEC_LAT0_WDMA_EXT MTK_M4U_ID(SMI_L23_ID, 5) +#define M4U_PORT_L23_HW_VDEC_UFO_ENC_EXT MTK_M4U_ID(SMI_L23_ID, 6) +#define M4U_PORT_L23_HW_VDEC_UFO_ENC_EXT_C MTK_M4U_ID(SMI_L23_ID, 7) +#define M4U_PORT_L23_HW_VDEC_MC_EXT_C MTK_M4U_ID(SMI_L23_ID, 8) + +/* LARB 27 -- CCU */ +#define M4U_PORT_L27_CCUI MTK_M4U_ID(SMI_L27_ID, 0) +#define M4U_PORT_L27_CCUO MTK_M4U_ID(SMI_L27_ID, 1) +#define M4U_PORT_L27_CCUI2 MTK_M4U_ID(SMI_L27_ID, 2) +#define M4U_PORT_L27_CCUO2 MTK_M4U_ID(SMI_L27_ID, 3) + +/* LARB 28 -- AXI-CCU */ +#define M4U_PORT_L28_CCU_AXI_0 MTK_M4U_ID(SMI_L28_ID, 0) + +/* infra/peri */ +#define IFR_IOMMU_PORT_PCIE_0 MTK_IFAIOMMU_PERI_ID(0) + +#endif -- GitLab From cf69ef46dbd980a0b1c956d668e066a73e0acd0f Mon Sep 17 00:00:00 2001 From: "Chengci.Xu" Date: Fri, 2 Jun 2023 17:02:22 +0800 Subject: [PATCH 0830/3445] iommu/mediatek: Fix two IOMMU share pagetable issue Prepare for mt8188 to fix a two IOMMU HWs share pagetable issue. We have two MM IOMMU HWs in mt8188, one is VPP-IOMMU, the other is VDO-IOMMU. The 2 MM IOMMU HWs share pagetable don't work in this case: a) VPP-IOMMU probe firstly. b) VDO-IOMMU probe. c) The master for VDO-IOMMU probe (means frstdata is vpp-iommu). d) The master in another domain probe. No matter it is vdo or vpp. Then it still create a new pagetable in step d). The problem is "frstdata->bank[0]->m4u_dom" was not initialized. Then when d) enter, it still create a new one. In this patch, we create a new variable "share_dom" for this share pgtable case, it should be helpful for readable. and put all the share pgtable logic in the mtk_iommu_domain_finalise. In mt8195, the master of VPP-IOMMU probes before than VDO-IOMMU from its dtsi node sequence, we don't see this issue in it. Prepare for mt8188. Fixes: 645b87c190c9 ("iommu/mediatek: Fix 2 HW sharing pgtable issue") Signed-off-by: Chengci.Xu Signed-off-by: Yong Wu Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Alexandre Mergnat Link: https://lore.kernel.org/r/20230602090227.7264-3-yong.wu@mediatek.com Signed-off-by: Joerg Roedel --- drivers/iommu/mtk_iommu.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index e93906d6e112e..c2764891a779c 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -258,6 +258,8 @@ struct mtk_iommu_data { struct device *smicomm_dev; struct mtk_iommu_bank_data *bank; + struct mtk_iommu_domain *share_dom; /* For 2 HWs share pgtable */ + struct regmap *pericfg; struct mutex mutex; /* Protect m4u_group/m4u_dom above */ @@ -620,15 +622,14 @@ static int mtk_iommu_domain_finalise(struct mtk_iommu_domain *dom, struct mtk_iommu_data *data, unsigned int region_id) { + struct mtk_iommu_domain *share_dom = data->share_dom; const struct mtk_iommu_iova_region *region; - struct mtk_iommu_domain *m4u_dom; - - /* Always use bank0 in sharing pgtable case */ - m4u_dom = data->bank[0].m4u_dom; - if (m4u_dom) { - dom->iop = m4u_dom->iop; - dom->cfg = m4u_dom->cfg; - dom->domain.pgsize_bitmap = m4u_dom->cfg.pgsize_bitmap; + + /* Always use share domain in sharing pgtable case */ + if (MTK_IOMMU_HAS_FLAG(data->plat_data, SHARE_PGTABLE) && share_dom) { + dom->iop = share_dom->iop; + dom->cfg = share_dom->cfg; + dom->domain.pgsize_bitmap = share_dom->cfg.pgsize_bitmap; goto update_iova_region; } @@ -658,6 +659,9 @@ static int mtk_iommu_domain_finalise(struct mtk_iommu_domain *dom, /* Update our support page sizes bitmap */ dom->domain.pgsize_bitmap = dom->cfg.pgsize_bitmap; + if (MTK_IOMMU_HAS_FLAG(data->plat_data, SHARE_PGTABLE)) + data->share_dom = dom; + update_iova_region: /* Update the iova region for this domain */ region = data->plat_data->iova_region + region_id; @@ -708,7 +712,9 @@ static int mtk_iommu_attach_device(struct iommu_domain *domain, /* Data is in the frstdata in sharing pgtable case. */ frstdata = mtk_iommu_get_frst_data(hw_list); + mutex_lock(&frstdata->mutex); ret = mtk_iommu_domain_finalise(dom, frstdata, region_id); + mutex_unlock(&frstdata->mutex); if (ret) { mutex_unlock(&dom->mutex); return ret; -- GitLab From 9a89051084af8ef566f3a2127cf5baa433dea497 Mon Sep 17 00:00:00 2001 From: "Chengci.Xu" Date: Fri, 2 Jun 2023 17:02:23 +0800 Subject: [PATCH 0831/3445] iommu/mediatek: Adjust mtk_iommu_config flow If there are many ports in a infra master, current flow will update the INFRA register many times. This patch saves all ports to portid_msk in the front of mtk_iommu_config(), then update only once for the IOMMU configure. After this, we could avoid send too many SMC calls to ATF in MT8188. Prepare for MT8188, also reduce the indention without functional change. Signed-off-by: Chengci.Xu Signed-off-by: Yong Wu Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Alexandre Mergnat Link: https://lore.kernel.org/r/20230602090227.7264-4-yong.wu@mediatek.com Signed-off-by: Joerg Roedel --- drivers/iommu/mtk_iommu.c | 58 +++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index c2764891a779c..e1146a5957328 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -579,41 +579,47 @@ static int mtk_iommu_config(struct mtk_iommu_data *data, struct device *dev, unsigned int larbid, portid; struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); const struct mtk_iommu_iova_region *region; - u32 peri_mmuen, peri_mmuen_msk; + unsigned long portid_msk = 0; int i, ret = 0; for (i = 0; i < fwspec->num_ids; ++i) { - larbid = MTK_M4U_TO_LARB(fwspec->ids[i]); portid = MTK_M4U_TO_PORT(fwspec->ids[i]); + portid_msk |= BIT(portid); + } - if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) { - larb_mmu = &data->larb_imu[larbid]; + if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) { + /* All ports should be in the same larb. just use 0 here */ + larbid = MTK_M4U_TO_LARB(fwspec->ids[0]); + larb_mmu = &data->larb_imu[larbid]; + region = data->plat_data->iova_region + regionid; - region = data->plat_data->iova_region + regionid; + for_each_set_bit(portid, &portid_msk, 32) larb_mmu->bank[portid] = upper_32_bits(region->iova_base); - dev_dbg(dev, "%s iommu for larb(%s) port %d region %d rgn-bank %d.\n", - enable ? "enable" : "disable", dev_name(larb_mmu->dev), - portid, regionid, larb_mmu->bank[portid]); - - if (enable) - larb_mmu->mmu |= MTK_SMI_MMU_EN(portid); - else - larb_mmu->mmu &= ~MTK_SMI_MMU_EN(portid); - } else if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_INFRA)) { - peri_mmuen_msk = BIT(portid); - /* PCI dev has only one output id, enable the next writing bit for PCIe */ - if (dev_is_pci(dev)) - peri_mmuen_msk |= BIT(portid + 1); - - peri_mmuen = enable ? peri_mmuen_msk : 0; - ret = regmap_update_bits(data->pericfg, PERICFG_IOMMU_1, - peri_mmuen_msk, peri_mmuen); - if (ret) - dev_err(dev, "%s iommu(%s) inframaster 0x%x fail(%d).\n", - enable ? "enable" : "disable", - dev_name(data->dev), peri_mmuen_msk, ret); + dev_dbg(dev, "%s iommu for larb(%s) port 0x%lx region %d rgn-bank %d.\n", + enable ? "enable" : "disable", dev_name(larb_mmu->dev), + portid_msk, regionid, upper_32_bits(region->iova_base)); + + if (enable) + larb_mmu->mmu |= portid_msk; + else + larb_mmu->mmu &= ~portid_msk; + } else if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_INFRA)) { + /* PCI dev has only one output id, enable the next writing bit for PCIe */ + if (dev_is_pci(dev)) { + if (fwspec->num_ids != 1) { + dev_err(dev, "PCI dev can only have one port.\n"); + return -ENODEV; + } + portid_msk |= BIT(portid + 1); } + + ret = regmap_update_bits(data->pericfg, PERICFG_IOMMU_1, + (u32)portid_msk, enable ? (u32)portid_msk : 0); + if (ret) + dev_err(dev, "%s iommu(%s) inframaster 0x%lx fail(%d).\n", + enable ? "enable" : "disable", + dev_name(data->dev), portid_msk, ret); } return ret; } -- GitLab From 946e719ce621fc409001bc05c942d08a37b9052e Mon Sep 17 00:00:00 2001 From: "Chengci.Xu" Date: Fri, 2 Jun 2023 17:02:24 +0800 Subject: [PATCH 0832/3445] iommu/mediatek: Add enable IOMMU SMC command for INFRA masters Prepare for MT8188. In MT8188, the register which enables IOMMU for INFRA masters are in the secure world for security concerns, therefore we add a SMC command for INFRA masters to enable IOMMU in ATF. Signed-off-by: Chengci.Xu Signed-off-by: Yong Wu Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Alexandre Mergnat Link: https://lore.kernel.org/r/20230602090227.7264-5-yong.wu@mediatek.com Signed-off-by: Joerg Roedel --- drivers/iommu/mtk_iommu.c | 32 ++++++++++++++++++++++---------- include/soc/mediatek/smi.h | 1 + 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index e1146a5957328..fe3839bb14f7c 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -3,6 +3,7 @@ * Copyright (c) 2015-2016 MediaTek Inc. * Author: Yong Wu */ +#include #include #include #include @@ -27,6 +28,7 @@ #include #include #include +#include #include #include @@ -143,6 +145,7 @@ #define PGTABLE_PA_35_EN BIT(17) #define TF_PORT_TO_ADDR_MT8173 BIT(18) #define INT_ID_PORT_WIDTH_6 BIT(19) +#define CFG_IFA_MASTER_IN_ATF BIT(20) #define MTK_IOMMU_HAS_FLAG_MASK(pdata, _x, mask) \ ((((pdata)->flags) & (mask)) == (_x)) @@ -580,6 +583,7 @@ static int mtk_iommu_config(struct mtk_iommu_data *data, struct device *dev, struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); const struct mtk_iommu_iova_region *region; unsigned long portid_msk = 0; + struct arm_smccc_res res; int i, ret = 0; for (i = 0; i < fwspec->num_ids; ++i) { @@ -605,17 +609,24 @@ static int mtk_iommu_config(struct mtk_iommu_data *data, struct device *dev, else larb_mmu->mmu &= ~portid_msk; } else if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_INFRA)) { - /* PCI dev has only one output id, enable the next writing bit for PCIe */ - if (dev_is_pci(dev)) { - if (fwspec->num_ids != 1) { - dev_err(dev, "PCI dev can only have one port.\n"); - return -ENODEV; + if (MTK_IOMMU_HAS_FLAG(data->plat_data, CFG_IFA_MASTER_IN_ATF)) { + arm_smccc_smc(MTK_SIP_KERNEL_IOMMU_CONTROL, + IOMMU_ATF_CMD_CONFIG_INFRA_IOMMU, + portid_msk, enable, 0, 0, 0, 0, &res); + ret = res.a0; + } else { + /* PCI dev has only one output id, enable the next writing bit for PCIe */ + if (dev_is_pci(dev)) { + if (fwspec->num_ids != 1) { + dev_err(dev, "PCI dev can only have one port.\n"); + return -ENODEV; + } + portid_msk |= BIT(portid + 1); } - portid_msk |= BIT(portid + 1); - } - ret = regmap_update_bits(data->pericfg, PERICFG_IOMMU_1, - (u32)portid_msk, enable ? (u32)portid_msk : 0); + ret = regmap_update_bits(data->pericfg, PERICFG_IOMMU_1, + (u32)portid_msk, enable ? (u32)portid_msk : 0); + } if (ret) dev_err(dev, "%s iommu(%s) inframaster 0x%lx fail(%d).\n", enable ? "enable" : "disable", @@ -1330,7 +1341,8 @@ static int mtk_iommu_probe(struct platform_device *pdev) dev_err_probe(dev, ret, "mm dts parse fail\n"); goto out_runtime_disable; } - } else if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_INFRA)) { + } else if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_INFRA) && + !MTK_IOMMU_HAS_FLAG(data->plat_data, CFG_IFA_MASTER_IN_ATF)) { p = data->plat_data->pericfg_comp_str; data->pericfg = syscon_regmap_lookup_by_compatible(p); if (IS_ERR(data->pericfg)) { diff --git a/include/soc/mediatek/smi.h b/include/soc/mediatek/smi.h index dfd8efca5e606..000eb1cf68b7a 100644 --- a/include/soc/mediatek/smi.h +++ b/include/soc/mediatek/smi.h @@ -13,6 +13,7 @@ enum iommu_atf_cmd { IOMMU_ATF_CMD_CONFIG_SMI_LARB, /* For mm master to en/disable iommu */ + IOMMU_ATF_CMD_CONFIG_INFRA_IOMMU, /* For infra master to enable iommu */ IOMMU_ATF_CMD_MAX, }; -- GitLab From a09e84034d87d3aa2f9ad584bebd92b0bab6e0be Mon Sep 17 00:00:00 2001 From: "Chengci.Xu" Date: Fri, 2 Jun 2023 17:02:25 +0800 Subject: [PATCH 0833/3445] iommu/mediatek: Add MT8188 IOMMU Support MT8188 has 3 IOMMU, containing 2 MM IOMMUs, one is for vdo, the other is for vpp. and 1 INFRA IOMMU. Signed-off-by: Chengci.Xu Signed-off-by: Yong Wu Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Alexandre Mergnat Link: https://lore.kernel.org/r/20230602090227.7264-6-yong.wu@mediatek.com Signed-off-by: Joerg Roedel --- drivers/iommu/mtk_iommu.c | 49 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index fe3839bb14f7c..33cfb226d949e 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -170,6 +170,7 @@ enum mtk_iommu_plat { M4U_MT8173, M4U_MT8183, M4U_MT8186, + M4U_MT8188, M4U_MT8192, M4U_MT8195, M4U_MT8365, @@ -1594,6 +1595,51 @@ static const struct mtk_iommu_plat_data mt8186_data_mm = { .iova_region_larb_msk = mt8186_larb_region_msk, }; +static const struct mtk_iommu_plat_data mt8188_data_infra = { + .m4u_plat = M4U_MT8188, + .flags = WR_THROT_EN | DCM_DISABLE | STD_AXI_MODE | PM_CLK_AO | + MTK_IOMMU_TYPE_INFRA | IFA_IOMMU_PCIE_SUPPORT | + PGTABLE_PA_35_EN | CFG_IFA_MASTER_IN_ATF, + .inv_sel_reg = REG_MMU_INV_SEL_GEN2, + .banks_num = 1, + .banks_enable = {true}, + .iova_region = single_domain, + .iova_region_nr = ARRAY_SIZE(single_domain), +}; + +static const struct mtk_iommu_plat_data mt8188_data_vdo = { + .m4u_plat = M4U_MT8188, + .flags = HAS_BCLK | HAS_SUB_COMM_3BITS | OUT_ORDER_WR_EN | + WR_THROT_EN | IOVA_34_EN | SHARE_PGTABLE | + PGTABLE_PA_35_EN | MTK_IOMMU_TYPE_MM, + .hw_list = &m4ulist, + .inv_sel_reg = REG_MMU_INV_SEL_GEN2, + .banks_num = 1, + .banks_enable = {true}, + .iova_region = mt8192_multi_dom, + .iova_region_nr = ARRAY_SIZE(mt8192_multi_dom), + .larbid_remap = {{2}, {0}, {21}, {0}, {19}, {9, 10, + 11 /* 11a */, 25 /* 11c */}, + {13, 0, 29 /* 16b */, 30 /* 17b */, 0}, {5}}, +}; + +static const struct mtk_iommu_plat_data mt8188_data_vpp = { + .m4u_plat = M4U_MT8188, + .flags = HAS_BCLK | HAS_SUB_COMM_3BITS | OUT_ORDER_WR_EN | + WR_THROT_EN | IOVA_34_EN | SHARE_PGTABLE | + PGTABLE_PA_35_EN | MTK_IOMMU_TYPE_MM, + .hw_list = &m4ulist, + .inv_sel_reg = REG_MMU_INV_SEL_GEN2, + .banks_num = 1, + .banks_enable = {true}, + .iova_region = mt8192_multi_dom, + .iova_region_nr = ARRAY_SIZE(mt8192_multi_dom), + .larbid_remap = {{1}, {3}, {23}, {7}, {MTK_INVALID_LARBID}, + {12, 15, 24 /* 11b */}, {14, MTK_INVALID_LARBID, + 16 /* 16a */, 17 /* 17a */, MTK_INVALID_LARBID, + 27, 28 /* ccu0 */, MTK_INVALID_LARBID}, {4, 6}}, +}; + static const unsigned int mt8192_larb_region_msk[MT8192_MULTI_REGION_NR_MAX][MTK_LARB_NR_MAX] = { [0] = {~0, ~0}, /* Region0: larb0/1 */ [1] = {0, 0, 0, 0, ~0, ~0, 0, ~0}, /* Region1: larb4/5/7 */ @@ -1702,6 +1748,9 @@ static const struct of_device_id mtk_iommu_of_ids[] = { { .compatible = "mediatek,mt8173-m4u", .data = &mt8173_data}, { .compatible = "mediatek,mt8183-m4u", .data = &mt8183_data}, { .compatible = "mediatek,mt8186-iommu-mm", .data = &mt8186_data_mm}, /* mm: m4u */ + { .compatible = "mediatek,mt8188-iommu-infra", .data = &mt8188_data_infra}, + { .compatible = "mediatek,mt8188-iommu-vdo", .data = &mt8188_data_vdo}, + { .compatible = "mediatek,mt8188-iommu-vpp", .data = &mt8188_data_vpp}, { .compatible = "mediatek,mt8192-m4u", .data = &mt8192_data}, { .compatible = "mediatek,mt8195-iommu-infra", .data = &mt8195_data_infra}, { .compatible = "mediatek,mt8195-iommu-vdo", .data = &mt8195_data_vdo}, -- GitLab From 1e8a46393a9579d2fe390d330edcd85623d2119d Mon Sep 17 00:00:00 2001 From: Yong Wu Date: Fri, 2 Jun 2023 17:02:26 +0800 Subject: [PATCH 0834/3445] iommu/mediatek: mt8188: Add iova_region_larb_msk Add iova_region_larb_msk for mt8188. We separate the 16GB iova regions by each device's larbid/portid. Refer to include/dt-bindings/memory/mediatek,mt8188-memory-port.h As commented in the code, larb19(21) means it's larb19 while its SW index is 21. Signed-off-by: Yong Wu Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Alexandre Mergnat Link: https://lore.kernel.org/r/20230602090227.7264-7-yong.wu@mediatek.com Signed-off-by: Joerg Roedel --- drivers/iommu/mtk_iommu.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index 33cfb226d949e..640275873a271 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -1607,6 +1607,20 @@ static const struct mtk_iommu_plat_data mt8188_data_infra = { .iova_region_nr = ARRAY_SIZE(single_domain), }; +static const u32 mt8188_larb_region_msk[MT8192_MULTI_REGION_NR_MAX][MTK_LARB_NR_MAX] = { + [0] = {~0, ~0, ~0, ~0}, /* Region0: all ports for larb0/1/2/3 */ + [1] = {0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, ~0, ~0, ~0}, /* Region1: larb19(21)/21(22)/23 */ + [2] = {0, 0, 0, 0, ~0, ~0, ~0, ~0, /* Region2: the other larbs. */ + ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, + ~0, ~0, ~0, ~0, ~0, 0, 0, 0, + 0, ~0}, + [3] = {0}, + [4] = {[24] = BIT(0) | BIT(1)}, /* Only larb27(24) port0/1 */ + [5] = {[24] = BIT(2) | BIT(3)}, /* Only larb27(24) port2/3 */ +}; + static const struct mtk_iommu_plat_data mt8188_data_vdo = { .m4u_plat = M4U_MT8188, .flags = HAS_BCLK | HAS_SUB_COMM_3BITS | OUT_ORDER_WR_EN | @@ -1618,6 +1632,7 @@ static const struct mtk_iommu_plat_data mt8188_data_vdo = { .banks_enable = {true}, .iova_region = mt8192_multi_dom, .iova_region_nr = ARRAY_SIZE(mt8192_multi_dom), + .iova_region_larb_msk = mt8188_larb_region_msk, .larbid_remap = {{2}, {0}, {21}, {0}, {19}, {9, 10, 11 /* 11a */, 25 /* 11c */}, {13, 0, 29 /* 16b */, 30 /* 17b */, 0}, {5}}, @@ -1634,6 +1649,7 @@ static const struct mtk_iommu_plat_data mt8188_data_vpp = { .banks_enable = {true}, .iova_region = mt8192_multi_dom, .iova_region_nr = ARRAY_SIZE(mt8192_multi_dom), + .iova_region_larb_msk = mt8188_larb_region_msk, .larbid_remap = {{1}, {3}, {23}, {7}, {MTK_INVALID_LARBID}, {12, 15, 24 /* 11b */}, {14, MTK_INVALID_LARBID, 16 /* 16a */, 17 /* 17a */, MTK_INVALID_LARBID, -- GitLab From 972f49c5faf64b50e8a7ef59c73e28103b22e988 Mon Sep 17 00:00:00 2001 From: Yong Wu Date: Fri, 2 Jun 2023 17:02:27 +0800 Subject: [PATCH 0835/3445] MAINTAINERS: iommu/mediatek: Update the header file name We add the prefix "mediatek," for the lastest ports header file name, For example, include/dt-bindings/memory/mediatek,mt8188-memory-port.h. Add a new entry for this. Signed-off-by: Yong Wu Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230602090227.7264-8-yong.wu@mediatek.com Signed-off-by: Joerg Roedel --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 3be1bdfe8ecc7..3eec0065be9d9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13238,6 +13238,7 @@ L: linux-mediatek@lists.infradead.org (moderated for non-subscribers) S: Supported F: Documentation/devicetree/bindings/iommu/mediatek* F: drivers/iommu/mtk_iommu* +F: include/dt-bindings/memory/mediatek,mt*-port.h F: include/dt-bindings/memory/mt*-port.h MEDIATEK JPEG DRIVER -- GitLab From aedd11e01db069123f3927ddce79f5376251c949 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 17 Jul 2023 15:14:40 +0200 Subject: [PATCH 0836/3445] iommu/ipmmu-vmsa: Convert to read_poll_timeout_atomic() Use read_poll_timeout_atomic() instead of open-coding the same operation. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/649c7e09841b998c5c8d7fc274884a85e4b5bfe9.1689599528.git.geert+renesas@glider.be Signed-off-by: Joerg Roedel --- drivers/iommu/ipmmu-vmsa.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index 9f64c5c9f5b90..3b58a8ea3bdef 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -253,17 +254,13 @@ static void ipmmu_imuctr_write(struct ipmmu_vmsa_device *mmu, /* Wait for any pending TLB invalidations to complete */ static void ipmmu_tlb_sync(struct ipmmu_vmsa_domain *domain) { - unsigned int count = 0; + u32 val; - while (ipmmu_ctx_read_root(domain, IMCTR) & IMCTR_FLUSH) { - cpu_relax(); - if (++count == TLB_LOOP_TIMEOUT) { - dev_err_ratelimited(domain->mmu->dev, + if (read_poll_timeout_atomic(ipmmu_ctx_read_root, val, + !(val & IMCTR_FLUSH), 1, TLB_LOOP_TIMEOUT, + false, domain, IMCTR)) + dev_err_ratelimited(domain->mmu->dev, "TLB sync timed out -- MMU may be deadlocked\n"); - return; - } - udelay(1); - } } static void ipmmu_tlb_invalidate(struct ipmmu_vmsa_domain *domain) -- GitLab From ed8c975b0f64ffc1e546fca26519974d8a446831 Mon Sep 17 00:00:00 2001 From: Min-Hua Chen Date: Fri, 21 Jul 2023 07:21:54 +0800 Subject: [PATCH 0837/3445] iommu/apple-dart: mark apple_dart_pm_ops static This patch fixes the following sparse warning: drivers/iommu/apple-dart.c:1279:1: sparse: warning: symbol 'apple_dart_pm_ops' was not declared. Should it be static? No functional change intended. Signed-off-by: Min-Hua Chen Acked-by: Sven Peter Link: https://lore.kernel.org/r/20230720232155.3923-1-minhuadotchen@gmail.com Signed-off-by: Joerg Roedel --- drivers/iommu/apple-dart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index 8af64b57f0483..2082081402d32 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -1276,7 +1276,7 @@ static __maybe_unused int apple_dart_resume(struct device *dev) return 0; } -DEFINE_SIMPLE_DEV_PM_OPS(apple_dart_pm_ops, apple_dart_suspend, apple_dart_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(apple_dart_pm_ops, apple_dart_suspend, apple_dart_resume); static const struct of_device_id apple_dart_of_match[] = { { .compatible = "apple,t8103-dart", .data = &apple_dart_hw_t8103 }, -- GitLab From d48a51286c698f7fe8efc688f23a532f4fe9a904 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 24 Jul 2023 14:36:05 -0300 Subject: [PATCH 0838/3445] iommu/sprd: Add missing force_aperture force_aperture was intended to false only by GART drivers that have an identity translation outside the aperture. This does not describe sprd, so add the missing 'force_aperture = true'. Fixes: b23e4fc4e3fa ("iommu: add Unisoc IOMMU basic driver") Signed-off-by: Jason Gunthorpe Acked-by: Chunyan Zhang Signed-off-by: Joerg Roedel --- drivers/iommu/sprd-iommu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iommu/sprd-iommu.c b/drivers/iommu/sprd-iommu.c index 39e34fdeccda7..eb684d8807cab 100644 --- a/drivers/iommu/sprd-iommu.c +++ b/drivers/iommu/sprd-iommu.c @@ -148,6 +148,7 @@ static struct iommu_domain *sprd_iommu_domain_alloc(unsigned int domain_type) dom->domain.geometry.aperture_start = 0; dom->domain.geometry.aperture_end = SZ_256M - 1; + dom->domain.geometry.force_aperture = true; return &dom->domain; } -- GitLab From 52a8fd24d129fb0e82fe6476dea35480d771365a Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 28 Jul 2023 10:46:59 +0900 Subject: [PATCH 0839/3445] iommu/ipmmu-vmsa: Allow PCIe devices IPMMU hardware on R-Car Gen3 and RZ/G2 is simple. Each bus-master device like eMMC host and PCIe controllers has a micro-TLB of The IPMMU, and after enabled it, all transactions of the device are under the IPMMU. eMMC host ---(micro-TLB of eMMC)--- IPMMU cache --- IPMMU main PCIe --------(micro-TLB of PCIe)--- IPMMU cache --- IPMMU main Now this IPMMU driver allows eMMC host, and it is safe to use the IPMMU. So, we can assume that it is safe to use the IPMMU from PCIe devices too, because all PCIe devices transactions will go to the micro-TLB of PCIe. So, add a new condition whether the device is a PCIe device or not in the ipmmu_device_is_allowed() which will be called if the PCIe host controller has iommu-map property. This can improve CPU load because the PCIe controllers only have a capability for lower 32-bit memory area so that this can avoid using swiotlb. Note that IPMMU on R-Car Gen4 is different than R-Car Gen3 and RZ/G2's one, especially OS-ID. But, for now, the IPMMU driver takes care of OS-ID 0 only. In other words, all PCIe devices will go to the micro-TLB of PCIe. Signed-off-by: Yoshihiro Shimoda Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230728014659.411751-1-yoshihiro.shimoda.uh@renesas.com Signed-off-by: Joerg Roedel --- drivers/iommu/ipmmu-vmsa.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index 3b58a8ea3bdef..c31552d6a5fad 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -720,6 +721,10 @@ static bool ipmmu_device_is_allowed(struct device *dev) if (soc_device_match(soc_denylist)) return false; + /* Check whether this device is a PCI device */ + if (dev_is_pci(dev)) + return true; + /* Check whether this device can work with the IPMMU */ for (i = 0; i < ARRAY_SIZE(devices_allowlist); i++) { if (!strcmp(dev_name(dev), devices_allowlist[i])) -- GitLab From 6b7867b5b8a6b14c487bf04a693ab424c7a8718d Mon Sep 17 00:00:00 2001 From: Zhu Wang Date: Mon, 31 Jul 2023 19:27:58 +0800 Subject: [PATCH 0840/3445] iommu: Remove kernel-doc warnings Remove kernel-doc warnings: drivers/iommu/iommu.c:3261: warning: Function parameter or member 'group' not described in 'iommu_group_release_dma_owner' drivers/iommu/iommu.c:3261: warning: Excess function parameter 'dev' description in 'iommu_group_release_dma_owner' drivers/iommu/iommu.c:3275: warning: Function parameter or member 'dev' not described in 'iommu_device_release_dma_owner' drivers/iommu/iommu.c:3275: warning: Excess function parameter 'group' description in 'iommu_device_release_dma_owner' Signed-off-by: Zhu Wang Fixes: 89395ccedbc1 ("iommu: Add device-centric DMA ownership interfaces") Reviewed-by: Jason Gunthorpe Link: https://lore.kernel.org/r/20230731112758.214775-1-wangzhu9@huawei.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index e67f6562da73b..c53a4942f7457 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -3216,7 +3216,7 @@ static void __iommu_release_dma_ownership(struct iommu_group *group) /** * iommu_group_release_dma_owner() - Release DMA ownership of a group - * @dev: The device + * @group: The group * * Release the DMA ownership claimed by iommu_group_claim_dma_owner(). */ @@ -3230,7 +3230,7 @@ EXPORT_SYMBOL_GPL(iommu_group_release_dma_owner); /** * iommu_device_release_dma_owner() - Release DMA ownership of a device - * @group: The device. + * @dev: The device. * * Release the DMA ownership claimed by iommu_device_claim_dma_owner(). */ -- GitLab From bcf847e4dbb8b1bc10a37533f079d582ee77cdf5 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 2 Aug 2023 21:32:01 +0800 Subject: [PATCH 0841/3445] iommu/amd: Remove unsued extern declaration amd_iommu_init_hardware() Commit 2c0ae1720c09 ("iommu/amd: Convert iommu initialization to state machine") left behind this. Signed-off-by: YueHaibing Reviewed-by: Suravee Suthikulpanit Link: https://lore.kernel.org/r/20230802133201.17512-1-yuehaibing@huawei.com Signed-off-by: Joerg Roedel --- include/linux/amd-iommu.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/amd-iommu.h b/include/linux/amd-iommu.h index 953e6f12fa1c3..99a5201d9e625 100644 --- a/include/linux/amd-iommu.h +++ b/include/linux/amd-iommu.h @@ -32,7 +32,6 @@ struct task_struct; struct pci_dev; extern int amd_iommu_detect(void); -extern int amd_iommu_init_hardware(void); /** * amd_iommu_init_device() - Init device for use with IOMMUv2 driver -- GitLab From f19fba1f79dc1fb298de7dcbaae9f6299381aeea Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Thu, 3 Aug 2023 01:45:21 -0700 Subject: [PATCH 0842/3445] RDMA/bnxt_re: Fix max_qp count for virtual functions Driver has not accounted QP1 for virtual functions when fetching device attributes and hence max_qp count is one less than active_qp count. Fixed driver so that it counts QP1 for virtual functions as well while fetching device attributes Fixes: ccd9d0d3dffc ("RDMA/bnxt_re: Enable RoCE on virtual functions") Signed-off-by: Saravanan Vajravel Signed-off-by: Kalesh AP Signed-off-by: Selvin Xavier Link: https://lore.kernel.org/r/1691052326-32143-2-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/main.c | 6 ++---- drivers/infiniband/hw/bnxt_re/qplib_sp.c | 7 +++---- drivers/infiniband/hw/bnxt_re/qplib_sp.h | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index d658e6798bbfd..bbda694e9a76a 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -1152,8 +1152,7 @@ static int bnxt_re_alloc_res(struct bnxt_re_dev *rdev) /* Configure and allocate resources for qplib */ rdev->qplib_res.rcfw = &rdev->rcfw; - rc = bnxt_qplib_get_dev_attr(&rdev->rcfw, &rdev->dev_attr, - rdev->is_virtfn); + rc = bnxt_qplib_get_dev_attr(&rdev->rcfw, &rdev->dev_attr); if (rc) goto fail; @@ -1531,8 +1530,7 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 wqe_mode) rdev->pacing.dbr_pacing = false; } } - rc = bnxt_qplib_get_dev_attr(&rdev->rcfw, &rdev->dev_attr, - rdev->is_virtfn); + rc = bnxt_qplib_get_dev_attr(&rdev->rcfw, &rdev->dev_attr); if (rc) goto disable_rcfw; diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c index 7e57faab4f782..b77928ac0217d 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c @@ -89,7 +89,7 @@ static void bnxt_qplib_query_version(struct bnxt_qplib_rcfw *rcfw, } int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, - struct bnxt_qplib_dev_attr *attr, bool vf) + struct bnxt_qplib_dev_attr *attr) { struct creq_query_func_resp resp = {}; struct bnxt_qplib_cmdqmsg msg = {}; @@ -121,9 +121,8 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, /* Extract the context from the side buffer */ attr->max_qp = le32_to_cpu(sb->max_qp); - /* max_qp value reported by FW for PF doesn't include the QP1 for PF */ - if (!vf) - attr->max_qp += 1; + /* max_qp value reported by FW doesn't include the QP1 */ + attr->max_qp += 1; attr->max_qp_rd_atom = sb->max_qp_rd_atom > BNXT_QPLIB_MAX_OUT_RD_ATOM ? BNXT_QPLIB_MAX_OUT_RD_ATOM : sb->max_qp_rd_atom; diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.h b/drivers/infiniband/hw/bnxt_re/qplib_sp.h index 264ef3cedc45b..d33c78b96217a 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.h @@ -322,7 +322,7 @@ int bnxt_qplib_update_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl, struct bnxt_qplib_gid *gid, u16 gid_idx, const u8 *smac); int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, - struct bnxt_qplib_dev_attr *attr, bool vf); + struct bnxt_qplib_dev_attr *attr); int bnxt_qplib_set_func_resources(struct bnxt_qplib_res *res, struct bnxt_qplib_rcfw *rcfw, struct bnxt_qplib_ctx *ctx); -- GitLab From fd28c8a8c7a10e7b53851129c6d8dc5945108fe9 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Thu, 3 Aug 2023 01:45:22 -0700 Subject: [PATCH 0843/3445] RDMA/bnxt_re: Remove a redundant flag After the cited commit, BNXT_RE_FLAG_GOT_MSIX is redundant. Remove it. Fixes: 303432211324 ("bnxt_en: Remove runtime interrupt vector allocation") Signed-off-by: Kalesh AP Signed-off-by: Selvin Xavier Link: https://lore.kernel.org/r/1691052326-32143-3-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/bnxt_re.h | 1 - drivers/infiniband/hw/bnxt_re/main.c | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/bnxt_re.h b/drivers/infiniband/hw/bnxt_re/bnxt_re.h index 03a13258b140f..9fd9849ebdd14 100644 --- a/drivers/infiniband/hw/bnxt_re/bnxt_re.h +++ b/drivers/infiniband/hw/bnxt_re/bnxt_re.h @@ -140,7 +140,6 @@ struct bnxt_re_dev { struct list_head list; unsigned long flags; #define BNXT_RE_FLAG_NETDEV_REGISTERED 0 -#define BNXT_RE_FLAG_GOT_MSIX 2 #define BNXT_RE_FLAG_HAVE_L2_REF 3 #define BNXT_RE_FLAG_RCFW_CHANNEL_EN 4 #define BNXT_RE_FLAG_QOS_WORK_REG 5 diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index bbda694e9a76a..2fe47b39bf747 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -1422,8 +1422,8 @@ static void bnxt_re_dev_uninit(struct bnxt_re_dev *rdev) bnxt_re_net_ring_free(rdev, rdev->rcfw.creq.ring_id, type); bnxt_qplib_free_rcfw_channel(&rdev->rcfw); } - if (test_and_clear_bit(BNXT_RE_FLAG_GOT_MSIX, &rdev->flags)) - rdev->num_msix = 0; + + rdev->num_msix = 0; if (rdev->pacing.dbr_pacing) bnxt_re_deinitialize_dbr_pacing(rdev); @@ -1480,7 +1480,6 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 wqe_mode) ibdev_dbg(&rdev->ibdev, "Got %d MSI-X vectors\n", rdev->en_dev->ulp_tbl->msix_requested); rdev->num_msix = rdev->en_dev->ulp_tbl->msix_requested; - set_bit(BNXT_RE_FLAG_GOT_MSIX, &rdev->flags); bnxt_re_query_hwrm_intf_version(rdev); -- GitLab From c9f3e4e1d862f67d42720fdb680f4d7da64d7cc5 Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Thu, 3 Aug 2023 01:45:23 -0700 Subject: [PATCH 0844/3445] RDMA/bnxt_re: Fix the sideband buffer size handling for FW commands bnxt_qplib_rcfw_alloc_sbuf allocates 24 bytes and it is better to fit on stack variables. This way we can avoid unwanted kmalloc call. Call dma_alloc_coherent directly instead of wrapper bnxt_qplib_rcfw_alloc_sbuf. Also, FW expects the side buffer needs to be aligned to BNXT_QPLIB_CMDQE_UNITS(16B). So align the size to have the extra padding bytes. Signed-off-by: Kashyap Desai Signed-off-by: Hongguang Gao Signed-off-by: Selvin Xavier Link: https://lore.kernel.org/r/1691052326-32143-4-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/qplib_fp.c | 38 +++++++------ drivers/infiniband/hw/bnxt_re/qplib_rcfw.c | 34 +----------- drivers/infiniband/hw/bnxt_re/qplib_sp.c | 63 +++++++++++----------- 3 files changed, 55 insertions(+), 80 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c index f9dee0d2da9c3..282e34e8739e4 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c @@ -709,7 +709,7 @@ int bnxt_qplib_query_srq(struct bnxt_qplib_res *res, struct bnxt_qplib_rcfw *rcfw = res->rcfw; struct creq_query_srq_resp resp = {}; struct bnxt_qplib_cmdqmsg msg = {}; - struct bnxt_qplib_rcfw_sbuf *sbuf; + struct bnxt_qplib_rcfw_sbuf sbuf; struct creq_query_srq_resp_sb *sb; struct cmdq_query_srq req = {}; int rc = 0; @@ -719,17 +719,20 @@ int bnxt_qplib_query_srq(struct bnxt_qplib_res *res, sizeof(req)); /* Configure the request */ - sbuf = bnxt_qplib_rcfw_alloc_sbuf(rcfw, sizeof(*sb)); - if (!sbuf) + sbuf.size = ALIGN(sizeof(*sb), BNXT_QPLIB_CMDQE_UNITS); + sbuf.sb = dma_alloc_coherent(&rcfw->pdev->dev, sbuf.size, + &sbuf.dma_addr, GFP_KERNEL); + if (!sbuf.sb) return -ENOMEM; - req.resp_size = sizeof(*sb) / BNXT_QPLIB_CMDQE_UNITS; + req.resp_size = sbuf.size / BNXT_QPLIB_CMDQE_UNITS; req.srq_cid = cpu_to_le32(srq->id); - sb = sbuf->sb; - bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, sbuf, sizeof(req), + sb = sbuf.sb; + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, &sbuf, sizeof(req), sizeof(resp), 0); rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); srq->threshold = le16_to_cpu(sb->srq_limit); - bnxt_qplib_rcfw_free_sbuf(rcfw, sbuf); + dma_free_coherent(&rcfw->pdev->dev, sbuf.size, + sbuf.sb, sbuf.dma_addr); return rc; } @@ -1347,24 +1350,26 @@ int bnxt_qplib_query_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) struct bnxt_qplib_rcfw *rcfw = res->rcfw; struct creq_query_qp_resp resp = {}; struct bnxt_qplib_cmdqmsg msg = {}; - struct bnxt_qplib_rcfw_sbuf *sbuf; + struct bnxt_qplib_rcfw_sbuf sbuf; struct creq_query_qp_resp_sb *sb; struct cmdq_query_qp req = {}; u32 temp32[4]; int i, rc = 0; + sbuf.size = ALIGN(sizeof(*sb), BNXT_QPLIB_CMDQE_UNITS); + sbuf.sb = dma_alloc_coherent(&rcfw->pdev->dev, sbuf.size, + &sbuf.dma_addr, GFP_KERNEL); + if (!sbuf.sb) + return -ENOMEM; + sb = sbuf.sb; + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, CMDQ_BASE_OPCODE_QUERY_QP, sizeof(req)); - sbuf = bnxt_qplib_rcfw_alloc_sbuf(rcfw, sizeof(*sb)); - if (!sbuf) - return -ENOMEM; - sb = sbuf->sb; - req.qp_cid = cpu_to_le32(qp->id); - req.resp_size = sizeof(*sb) / BNXT_QPLIB_CMDQE_UNITS; - bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, sbuf, sizeof(req), + req.resp_size = sbuf.size / BNXT_QPLIB_CMDQE_UNITS; + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, &sbuf, sizeof(req), sizeof(resp), 0); rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) @@ -1423,7 +1428,8 @@ int bnxt_qplib_query_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) memcpy(qp->smac, sb->src_mac, 6); qp->vlan_id = le16_to_cpu(sb->vlan_pcp_vlan_dei_vlan_id); bail: - bnxt_qplib_rcfw_free_sbuf(rcfw, sbuf); + dma_free_coherent(&rcfw->pdev->dev, sbuf.size, + sbuf.sb, sbuf.dma_addr); return rc; } diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index b30e66b64827b..9d26871af2964 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -335,7 +335,8 @@ static int __send_message(struct bnxt_qplib_rcfw *rcfw, cpu_to_le64(sbuf->dma_addr)); __set_cmdq_base_resp_size(msg->req, msg->req_sz, ALIGN(sbuf->size, - BNXT_QPLIB_CMDQE_UNITS)); + BNXT_QPLIB_CMDQE_UNITS) / + BNXT_QPLIB_CMDQE_UNITS); } preq = (u8 *)msg->req; @@ -1196,34 +1197,3 @@ int bnxt_qplib_enable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw, return 0; } - -struct bnxt_qplib_rcfw_sbuf *bnxt_qplib_rcfw_alloc_sbuf( - struct bnxt_qplib_rcfw *rcfw, - u32 size) -{ - struct bnxt_qplib_rcfw_sbuf *sbuf; - - sbuf = kzalloc(sizeof(*sbuf), GFP_KERNEL); - if (!sbuf) - return NULL; - - sbuf->size = size; - sbuf->sb = dma_alloc_coherent(&rcfw->pdev->dev, sbuf->size, - &sbuf->dma_addr, GFP_KERNEL); - if (!sbuf->sb) - goto bail; - - return sbuf; -bail: - kfree(sbuf); - return NULL; -} - -void bnxt_qplib_rcfw_free_sbuf(struct bnxt_qplib_rcfw *rcfw, - struct bnxt_qplib_rcfw_sbuf *sbuf) -{ - if (sbuf->sb) - dma_free_coherent(&rcfw->pdev->dev, sbuf->size, - sbuf->sb, sbuf->dma_addr); - kfree(sbuf); -} diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c index b77928ac0217d..05ee8fdb44ad7 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c @@ -94,7 +94,7 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, struct creq_query_func_resp resp = {}; struct bnxt_qplib_cmdqmsg msg = {}; struct creq_query_func_resp_sb *sb; - struct bnxt_qplib_rcfw_sbuf *sbuf; + struct bnxt_qplib_rcfw_sbuf sbuf; struct cmdq_query_func req = {}; u8 *tqm_alloc; int i, rc = 0; @@ -104,16 +104,14 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, CMDQ_BASE_OPCODE_QUERY_FUNC, sizeof(req)); - sbuf = bnxt_qplib_rcfw_alloc_sbuf(rcfw, sizeof(*sb)); - if (!sbuf) { - dev_err(&rcfw->pdev->dev, - "SP: QUERY_FUNC alloc side buffer failed\n"); + sbuf.size = ALIGN(sizeof(*sb), BNXT_QPLIB_CMDQE_UNITS); + sbuf.sb = dma_alloc_coherent(&rcfw->pdev->dev, sbuf.size, + &sbuf.dma_addr, GFP_KERNEL); + if (!sbuf.sb) return -ENOMEM; - } - - sb = sbuf->sb; - req.resp_size = sizeof(*sb) / BNXT_QPLIB_CMDQE_UNITS; - bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, sbuf, sizeof(req), + sb = sbuf.sb; + req.resp_size = sbuf.size / BNXT_QPLIB_CMDQE_UNITS; + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, &sbuf, sizeof(req), sizeof(resp), 0); rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) @@ -174,7 +172,8 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, attr->is_atomic = bnxt_qplib_is_atomic_cap(rcfw); bail: - bnxt_qplib_rcfw_free_sbuf(rcfw, sbuf); + dma_free_coherent(&rcfw->pdev->dev, sbuf.size, + sbuf.sb, sbuf.dma_addr); return rc; } @@ -717,23 +716,22 @@ int bnxt_qplib_get_roce_stats(struct bnxt_qplib_rcfw *rcfw, struct creq_query_roce_stats_resp_sb *sb; struct cmdq_query_roce_stats req = {}; struct bnxt_qplib_cmdqmsg msg = {}; - struct bnxt_qplib_rcfw_sbuf *sbuf; + struct bnxt_qplib_rcfw_sbuf sbuf; int rc = 0; bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, CMDQ_BASE_OPCODE_QUERY_ROCE_STATS, sizeof(req)); - sbuf = bnxt_qplib_rcfw_alloc_sbuf(rcfw, sizeof(*sb)); - if (!sbuf) { - dev_err(&rcfw->pdev->dev, - "SP: QUERY_ROCE_STATS alloc side buffer failed\n"); + sbuf.size = ALIGN(sizeof(*sb), BNXT_QPLIB_CMDQE_UNITS); + sbuf.sb = dma_alloc_coherent(&rcfw->pdev->dev, sbuf.size, + &sbuf.dma_addr, GFP_KERNEL); + if (!sbuf.sb) return -ENOMEM; - } + sb = sbuf.sb; - sb = sbuf->sb; - req.resp_size = sizeof(*sb) / BNXT_QPLIB_CMDQE_UNITS; - bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, sbuf, sizeof(req), + req.resp_size = sbuf.size / BNXT_QPLIB_CMDQE_UNITS; + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, &sbuf, sizeof(req), sizeof(resp), 0); rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) @@ -789,7 +787,8 @@ int bnxt_qplib_get_roce_stats(struct bnxt_qplib_rcfw *rcfw, } bail: - bnxt_qplib_rcfw_free_sbuf(rcfw, sbuf); + dma_free_coherent(&rcfw->pdev->dev, sbuf.size, + sbuf.sb, sbuf.dma_addr); return rc; } @@ -800,32 +799,31 @@ int bnxt_qplib_qext_stat(struct bnxt_qplib_rcfw *rcfw, u32 fid, struct creq_query_roce_stats_ext_resp_sb *sb; struct cmdq_query_roce_stats_ext req = {}; struct bnxt_qplib_cmdqmsg msg = {}; - struct bnxt_qplib_rcfw_sbuf *sbuf; + struct bnxt_qplib_rcfw_sbuf sbuf; int rc; - sbuf = bnxt_qplib_rcfw_alloc_sbuf(rcfw, sizeof(*sb)); - if (!sbuf) { - dev_err(&rcfw->pdev->dev, - "SP: QUERY_ROCE_STATS_EXT alloc sb failed"); + sbuf.size = ALIGN(sizeof(*sb), BNXT_QPLIB_CMDQE_UNITS); + sbuf.sb = dma_alloc_coherent(&rcfw->pdev->dev, sbuf.size, + &sbuf.dma_addr, GFP_KERNEL); + if (!sbuf.sb) return -ENOMEM; - } + sb = sbuf.sb; bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, CMDQ_QUERY_ROCE_STATS_EXT_OPCODE_QUERY_ROCE_STATS, sizeof(req)); - req.resp_size = ALIGN(sizeof(*sb), BNXT_QPLIB_CMDQE_UNITS); - req.resp_addr = cpu_to_le64(sbuf->dma_addr); + req.resp_size = sbuf.size / BNXT_QPLIB_CMDQE_UNITS; + req.resp_addr = cpu_to_le64(sbuf.dma_addr); req.function_id = cpu_to_le32(fid); req.flags = cpu_to_le16(CMDQ_QUERY_ROCE_STATS_EXT_FLAGS_FUNCTION_ID); - bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, sbuf, sizeof(req), + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, &sbuf, sizeof(req), sizeof(resp), 0); rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); if (rc) goto bail; - sb = sbuf->sb; estat->tx_atomic_req = le64_to_cpu(sb->tx_atomic_req_pkts); estat->tx_read_req = le64_to_cpu(sb->tx_read_req_pkts); estat->tx_read_res = le64_to_cpu(sb->tx_read_res_pkts); @@ -849,7 +847,8 @@ int bnxt_qplib_qext_stat(struct bnxt_qplib_rcfw *rcfw, u32 fid, estat->rx_ecn_marked = le64_to_cpu(sb->rx_ecn_marked_pkts); bail: - bnxt_qplib_rcfw_free_sbuf(rcfw, sbuf); + dma_free_coherent(&rcfw->pdev->dev, sbuf.size, + sbuf.sb, sbuf.dma_addr); return rc; } -- GitLab From e59a5cec3f8ac79dcc1ed45af5975e529fbcde18 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Thu, 3 Aug 2023 01:45:24 -0700 Subject: [PATCH 0845/3445] RDMA/bnxt_re: Cleanup bnxt_re_process_raw_qp_pkt_rx() function - Remove unnecessary memset by initializing the variables during declaration itself. - Arranged variable declarartion in RCT order. Signed-off-by: Kalesh AP Signed-off-by: Selvin Xavier Link: https://lore.kernel.org/r/1691052326-32143-5-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index c46fd2a47c959..1ce3922d9c973 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -3333,26 +3333,21 @@ static int bnxt_re_process_raw_qp_pkt_rx(struct bnxt_re_qp *gsi_qp, struct bnxt_re_dev *rdev = gsi_qp->rdev; struct bnxt_re_sqp_entries *sqp_entry = NULL; struct bnxt_re_qp *gsi_sqp = rdev->gsi_ctx.gsi_sqp; + dma_addr_t shrq_hdr_buf_map; + struct ib_sge s_sge[2] = {}; + struct ib_sge r_sge[2] = {}; struct bnxt_re_ah *gsi_sah; + struct ib_recv_wr rwr = {}; + dma_addr_t rq_hdr_buf_map; + struct ib_ud_wr udwr = {}; struct ib_send_wr *swr; - struct ib_ud_wr udwr; - struct ib_recv_wr rwr; + u32 skip_bytes = 0; int pkt_type = 0; - u32 tbl_idx; void *rq_hdr_buf; - dma_addr_t rq_hdr_buf_map; - dma_addr_t shrq_hdr_buf_map; u32 offset = 0; - u32 skip_bytes = 0; - struct ib_sge s_sge[2]; - struct ib_sge r_sge[2]; + u32 tbl_idx; int rc; - memset(&udwr, 0, sizeof(udwr)); - memset(&rwr, 0, sizeof(rwr)); - memset(&s_sge, 0, sizeof(s_sge)); - memset(&r_sge, 0, sizeof(r_sge)); - swr = &udwr.wr; tbl_idx = cqe->wr_id; -- GitLab From 00d0427fd8ce034fb7f5257253806b2a8a0843e7 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Thu, 3 Aug 2023 01:45:25 -0700 Subject: [PATCH 0846/3445] RDMA/bnxt_re: Avoid unnecessary memset Avoid memset by initializing the variables during declaration itself. Signed-off-by: Kalesh AP Signed-off-by: Selvin Xavier Link: https://lore.kernel.org/r/1691052326-32143-6-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 1 - drivers/infiniband/hw/bnxt_re/main.c | 12 ++++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index 1ce3922d9c973..003a07c69bc52 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -2797,7 +2797,6 @@ static int bnxt_re_post_recv_shadow_qp(struct bnxt_re_dev *rdev, struct bnxt_qplib_swqe wqe; int rc = 0; - memset(&wqe, 0, sizeof(wqe)); while (wr) { /* House keeping */ memset(&wqe, 0, sizeof(wqe)); diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index 2fe47b39bf747..c7286945fecad 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -395,10 +395,9 @@ static int bnxt_re_hwrm_qcfg(struct bnxt_re_dev *rdev, u32 *db_len, struct bnxt_en_dev *en_dev = rdev->en_dev; struct hwrm_func_qcfg_output resp = {0}; struct hwrm_func_qcfg_input req = {0}; - struct bnxt_fw_msg fw_msg; + struct bnxt_fw_msg fw_msg = {}; int rc; - memset(&fw_msg, 0, sizeof(fw_msg)); bnxt_re_init_hwrm_hdr((void *)&req, HWRM_FUNC_QCFG); req.fid = cpu_to_le16(0xffff); bnxt_re_fill_fw_msg(&fw_msg, (void *)&req, sizeof(req), (void *)&resp, @@ -969,7 +968,7 @@ static int bnxt_re_handle_unaffi_async_event(struct creq_func_event static int bnxt_re_handle_qp_async_event(struct creq_qp_event *qp_event, struct bnxt_re_qp *qp) { - struct ib_event event; + struct ib_event event = {}; unsigned int flags; if (qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_ERR && @@ -979,7 +978,6 @@ static int bnxt_re_handle_qp_async_event(struct creq_qp_event *qp_event, bnxt_re_unlock_cqs(qp, flags); } - memset(&event, 0, sizeof(event)); if (qp->qplib_qp.srq) { event.device = &qp->rdev->ibdev; event.element.qp = &qp->ib_qp; @@ -1299,11 +1297,10 @@ static u32 bnxt_re_get_priority_mask(struct bnxt_re_dev *rdev) { u32 prio_map = 0, tmp_map = 0; struct net_device *netdev; - struct dcb_app app; + struct dcb_app app = {}; netdev = rdev->netdev; - memset(&app, 0, sizeof(app)); app.selector = IEEE_8021QAZ_APP_SEL_ETHERTYPE; app.protocol = ETH_P_IBOE; tmp_map = dcb_ieee_getapp_mask(netdev, &app); @@ -1445,15 +1442,14 @@ static void bnxt_re_worker(struct work_struct *work) static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 wqe_mode) { + struct bnxt_re_ring_attr rattr = {}; struct bnxt_qplib_creq_ctx *creq; - struct bnxt_re_ring_attr rattr; u32 db_offt; int vid; u8 type; int rc; /* Registered a new RoCE device instance to netdev */ - memset(&rattr, 0, sizeof(rattr)); rc = bnxt_re_register_netdev(rdev); if (rc) { ibdev_err(&rdev->ibdev, -- GitLab From 14611b9b984125b2da5966d0725fdd89f6564c45 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Thu, 3 Aug 2023 01:45:26 -0700 Subject: [PATCH 0847/3445] RDMA/bnxt_re: Remove unnecessary variable initializations Remove unnecessary variable initializations. Signed-off-by: Kalesh AP Signed-off-by: Selvin Xavier Link: https://lore.kernel.org/r/1691052326-32143-7-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 14 +++++++------- drivers/infiniband/hw/bnxt_re/main.c | 12 ++++++------ drivers/infiniband/hw/bnxt_re/qplib_fp.c | 6 +++--- drivers/infiniband/hw/bnxt_re/qplib_rcfw.c | 2 +- drivers/infiniband/hw/bnxt_re/qplib_res.c | 8 ++++---- drivers/infiniband/hw/bnxt_re/qplib_sp.c | 8 ++++---- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index 003a07c69bc52..c0a7181247f6d 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -284,7 +284,7 @@ int bnxt_re_query_gid(struct ib_device *ibdev, u32 port_num, int index, union ib_gid *gid) { struct bnxt_re_dev *rdev = to_bnxt_re_dev(ibdev, ibdev); - int rc = 0; + int rc; /* Ignore port_num */ memset(gid, 0, sizeof(*gid)); @@ -684,7 +684,7 @@ int bnxt_re_destroy_ah(struct ib_ah *ib_ah, u32 flags) struct bnxt_re_ah *ah = container_of(ib_ah, struct bnxt_re_ah, ib_ah); struct bnxt_re_dev *rdev = ah->rdev; bool block = true; - int rc = 0; + int rc; block = !(flags & RDMA_DESTROY_AH_SLEEPABLE); rc = bnxt_qplib_destroy_ah(&rdev->qplib_res, &ah->qplib_ah, block); @@ -834,7 +834,7 @@ static int bnxt_re_destroy_gsi_sqp(struct bnxt_re_qp *qp) struct bnxt_re_qp *gsi_sqp; struct bnxt_re_ah *gsi_sah; struct bnxt_re_dev *rdev; - int rc = 0; + int rc; rdev = qp->rdev; gsi_sqp = rdev->gsi_ctx.gsi_sqp; @@ -1441,7 +1441,7 @@ static int bnxt_re_create_gsi_qp(struct bnxt_re_qp *qp, struct bnxt_re_pd *pd, { struct bnxt_re_dev *rdev; struct bnxt_qplib_qp *qplqp; - int rc = 0; + int rc; rdev = qp->rdev; qplqp = &qp->qplib_qp; @@ -1872,7 +1872,7 @@ static int bnxt_re_modify_shadow_qp(struct bnxt_re_dev *rdev, int qp_attr_mask) { struct bnxt_re_qp *qp = rdev->gsi_ctx.gsi_sqp; - int rc = 0; + int rc; if (qp_attr_mask & IB_QP_STATE) { qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_STATE; @@ -2222,7 +2222,7 @@ static int bnxt_re_build_qp1_send_v2(struct bnxt_re_qp *qp, u8 ip_version = 0; u16 vlan_id = 0xFFFF; void *buf; - int i, rc = 0; + int i, rc; memset(&qp->qp1_hdr, 0, sizeof(qp->qp1_hdr)); @@ -3586,7 +3586,7 @@ static int send_phantom_wqe(struct bnxt_re_qp *qp) { struct bnxt_qplib_qp *lib_qp = &qp->qplib_qp; unsigned long flags; - int rc = 0; + int rc; spin_lock_irqsave(&qp->sq_lock, flags); diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index c7286945fecad..f34ce490500fd 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -360,7 +360,7 @@ static struct bnxt_ulp_ops bnxt_re_ulp_ops = { static int bnxt_re_register_netdev(struct bnxt_re_dev *rdev) { struct bnxt_en_dev *en_dev; - int rc = 0; + int rc; en_dev = rdev->en_dev; @@ -1145,7 +1145,7 @@ static int bnxt_re_alloc_res(struct bnxt_re_dev *rdev) { struct bnxt_re_ring_attr rattr = {}; int num_vec_created = 0; - int rc = 0, i; + int rc, i; u8 type; /* Configure and allocate resources for qplib */ @@ -1343,7 +1343,7 @@ static void bnxt_re_query_hwrm_intf_version(struct bnxt_re_dev *rdev) struct hwrm_ver_get_input req = {}; struct bnxt_qplib_chip_ctx *cctx; struct bnxt_fw_msg fw_msg = {}; - int rc = 0; + int rc; bnxt_re_init_hwrm_hdr((void *)&req, HWRM_VER_GET); req.hwrm_intf_maj = HWRM_VERSION_MAJOR; @@ -1373,7 +1373,7 @@ static void bnxt_re_query_hwrm_intf_version(struct bnxt_re_dev *rdev) static int bnxt_re_ib_init(struct bnxt_re_dev *rdev) { - int rc = 0; + int rc; u32 event; /* Register ib dev */ @@ -1613,7 +1613,7 @@ static int bnxt_re_add_device(struct auxiliary_device *adev, u8 wqe_mode) container_of(adev, struct bnxt_aux_priv, aux_dev); struct bnxt_en_dev *en_dev; struct bnxt_re_dev *rdev; - int rc = 0; + int rc; /* en_dev should never be NULL as long as adev and aux_dev are valid. */ en_dev = aux_priv->edev; @@ -1859,7 +1859,7 @@ static struct auxiliary_driver bnxt_re_driver = { static int __init bnxt_re_mod_init(void) { - int rc = 0; + int rc; pr_info("%s: %s", ROCE_DRV_MODULE_NAME, version); rc = auxiliary_driver_register(&bnxt_re_driver); diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c index 282e34e8739e4..db9890e14ae93 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c @@ -517,7 +517,7 @@ int bnxt_qplib_enable_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq, cqn_handler_t cqn_handler, srqn_handler_t srqn_handler) { - int rc = -1; + int rc; nq->pdev = pdev; nq->cqn_handler = cqn_handler; @@ -712,7 +712,7 @@ int bnxt_qplib_query_srq(struct bnxt_qplib_res *res, struct bnxt_qplib_rcfw_sbuf sbuf; struct creq_query_srq_resp_sb *sb; struct cmdq_query_srq req = {}; - int rc = 0; + int rc; bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, CMDQ_BASE_OPCODE_QUERY_SRQ, @@ -1354,7 +1354,7 @@ int bnxt_qplib_query_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) struct creq_query_qp_resp_sb *sb; struct cmdq_query_qp req = {}; u32 temp32[4]; - int i, rc = 0; + int i, rc; sbuf.size = ALIGN(sizeof(*sb), BNXT_QPLIB_CMDQE_UNITS); sbuf.sb = dma_alloc_coherent(&rcfw->pdev->dev, sbuf.size, diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index 9d26871af2964..287117ec50eed 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -488,7 +488,7 @@ static int __bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw, struct bnxt_qplib_crsqe *crsqe; unsigned long flags; u16 cookie; - int rc = 0; + int rc; u8 opcode; opcode = __get_cmdq_base_opcode(msg->req, msg->req_sz); diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.c b/drivers/infiniband/hw/bnxt_re/qplib_res.c index d47764c384611..6f1e8b721ad0b 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c @@ -385,7 +385,7 @@ static int bnxt_qplib_alloc_tqm_rings(struct bnxt_qplib_res *res, struct bnxt_qplib_hwq_attr hwq_attr = {}; struct bnxt_qplib_sg_info sginfo = {}; struct bnxt_qplib_tqm_ctx *tqmctx; - int rc = 0; + int rc; int i; tqmctx = &ctx->tqm_ctx; @@ -463,7 +463,7 @@ static void bnxt_qplib_map_tqm_pgtbl(struct bnxt_qplib_tqm_ctx *ctx) static int bnxt_qplib_setup_tqm_rings(struct bnxt_qplib_res *res, struct bnxt_qplib_ctx *ctx) { - int rc = 0; + int rc; rc = bnxt_qplib_alloc_tqm_rings(res, ctx); if (rc) @@ -501,7 +501,7 @@ int bnxt_qplib_alloc_ctx(struct bnxt_qplib_res *res, { struct bnxt_qplib_hwq_attr hwq_attr = {}; struct bnxt_qplib_sg_info sginfo = {}; - int rc = 0; + int rc; if (virt_fn || is_p5) goto stats_alloc; @@ -876,7 +876,7 @@ int bnxt_qplib_alloc_res(struct bnxt_qplib_res *res, struct pci_dev *pdev, struct net_device *netdev, struct bnxt_qplib_dev_attr *dev_attr) { - int rc = 0; + int rc; res->pdev = pdev; res->netdev = netdev; diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c index 05ee8fdb44ad7..a27b685151647 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c @@ -72,7 +72,7 @@ static void bnxt_qplib_query_version(struct bnxt_qplib_rcfw *rcfw, struct creq_query_version_resp resp = {}; struct bnxt_qplib_cmdqmsg msg = {}; struct cmdq_query_version req = {}; - int rc = 0; + int rc; bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, CMDQ_BASE_OPCODE_QUERY_VERSION, @@ -97,7 +97,7 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw, struct bnxt_qplib_rcfw_sbuf sbuf; struct cmdq_query_func req = {}; u8 *tqm_alloc; - int i, rc = 0; + int i, rc; u32 temp; bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, @@ -184,7 +184,7 @@ int bnxt_qplib_set_func_resources(struct bnxt_qplib_res *res, struct creq_set_func_resources_resp resp = {}; struct cmdq_set_func_resources req = {}; struct bnxt_qplib_cmdqmsg msg = {}; - int rc = 0; + int rc; bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, CMDQ_BASE_OPCODE_SET_FUNC_RESOURCES, @@ -717,7 +717,7 @@ int bnxt_qplib_get_roce_stats(struct bnxt_qplib_rcfw *rcfw, struct cmdq_query_roce_stats req = {}; struct bnxt_qplib_cmdqmsg msg = {}; struct bnxt_qplib_rcfw_sbuf sbuf; - int rc = 0; + int rc; bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, CMDQ_BASE_OPCODE_QUERY_ROCE_STATS, -- GitLab From df1bcf90a66a10967a3a43510b42cb3566208011 Mon Sep 17 00:00:00 2001 From: Chengchang Tang Date: Fri, 4 Aug 2023 09:27:08 +0800 Subject: [PATCH 0848/3445] RDMA/hns: Fix port active speed HW supports a variety of different speed, but the current speed is fixed. The real speed should be querried from ethernet. Fixes: 9a4435375cd1 ("IB/hns: Add driver files for hns RoCE driver") Signed-off-by: Chengchang Tang Signed-off-by: Junxian Huang Link: https://lore.kernel.org/r/20230804012711.808069-2-huangjunxian6@hisilicon.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/hns/hns_roce_main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 485e110ca4333..9141eadf33d2a 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -219,6 +219,7 @@ static int hns_roce_query_port(struct ib_device *ib_dev, u32 port_num, unsigned long flags; enum ib_mtu mtu; u32 port; + int ret; port = port_num - 1; @@ -231,8 +232,10 @@ static int hns_roce_query_port(struct ib_device *ib_dev, u32 port_num, IB_PORT_BOOT_MGMT_SUP; props->max_msg_sz = HNS_ROCE_MAX_MSG_LEN; props->pkey_tbl_len = 1; - props->active_width = IB_WIDTH_4X; - props->active_speed = 1; + ret = ib_get_eth_speed(ib_dev, port_num, &props->active_speed, + &props->active_width); + if (ret) + ibdev_warn(ib_dev, "failed to get speed, ret = %d.\n", ret); spin_lock_irqsave(&hr_dev->iboe.lock, flags); -- GitLab From 706efac4477cdb8be857f6322457de524acc02ff Mon Sep 17 00:00:00 2001 From: Junxian Huang Date: Fri, 4 Aug 2023 09:27:09 +0800 Subject: [PATCH 0849/3445] RDMA/hns: Fix incorrect post-send with direct wqe of wr-list Currently, direct wqe is not supported for wr-list. RoCE driver excludes direct wqe for wr-list by judging whether the number of wr is 1. For a wr-list where the second wr is a length-error atomic wr, the post-send driver handles the first wr and adds 1 to the wr number counter firstly. While handling the second wr, the driver finds out a length error and terminates the wr handle process, remaining the counter at 1. This causes the driver mistakenly judges there is only 1 wr and thus enters the direct wqe process, carrying the current length-error atomic wqe. This patch fixes the error by adding a judgement whether the current wr is a bad wr. If so, use the normal doorbell process but not direct wqe despite the wr number is 1. Fixes: 01584a5edcc4 ("RDMA/hns: Add support of direct wqe") Signed-off-by: Junxian Huang Link: https://lore.kernel.org/r/20230804012711.808069-3-huangjunxian6@hisilicon.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 30451cef5376e..97ff7f76fad5b 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -750,7 +750,8 @@ out: qp->sq.head += nreq; qp->next_sge = sge_idx; - if (nreq == 1 && (qp->en_flags & HNS_ROCE_QP_CAP_DIRECT_WQE)) + if (nreq == 1 && !ret && + (qp->en_flags & HNS_ROCE_QP_CAP_DIRECT_WQE)) write_dwqe(hr_dev, qp, wqe); else update_sq_db(hr_dev, qp); -- GitLab From c9c0bd3c177d93d80968f720304087ba83fe8f74 Mon Sep 17 00:00:00 2001 From: Junxian Huang Date: Fri, 4 Aug 2023 09:27:10 +0800 Subject: [PATCH 0850/3445] RDMA/hns: Fix inaccurate error label name in init instance This patch fixes inaccurate error label name in init instance. Fixes: 70f92521584f ("RDMA/hns: Use the reserved loopback QPs to free MR before destroying MPT") Signed-off-by: Junxian Huang Link: https://lore.kernel.org/r/20230804012711.808069-4-huangjunxian6@hisilicon.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 97ff7f76fad5b..eef143388f657 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -6658,14 +6658,14 @@ static int __hns_roce_hw_v2_init_instance(struct hnae3_handle *handle) ret = hns_roce_init(hr_dev); if (ret) { dev_err(hr_dev->dev, "RoCE Engine init failed!\n"); - goto error_failed_cfg; + goto error_failed_roce_init; } if (hr_dev->pci_dev->revision == PCI_REVISION_ID_HIP08) { ret = free_mr_init(hr_dev); if (ret) { dev_err(hr_dev->dev, "failed to init free mr!\n"); - goto error_failed_roce_init; + goto error_failed_free_mr_init; } } @@ -6673,10 +6673,10 @@ static int __hns_roce_hw_v2_init_instance(struct hnae3_handle *handle) return 0; -error_failed_roce_init: +error_failed_free_mr_init: hns_roce_exit(hr_dev); -error_failed_cfg: +error_failed_roce_init: kfree(hr_dev->priv); error_failed_kzalloc: -- GitLab From 9e03dbea2b0634b21a45946b4f8097e0dc86ebe1 Mon Sep 17 00:00:00 2001 From: Chengchang Tang Date: Fri, 4 Aug 2023 09:27:11 +0800 Subject: [PATCH 0851/3445] RDMA/hns: Fix CQ and QP cache affinity Currently, the affinity between QP cache and CQ cache is not considered when assigning QPN, it will affect the message rate of HW. Allocate QPN from QP cache with better CQ affinity to get better performance. Fixes: 71586dd20010 ("RDMA/hns: Create QP with selected QPN for bank load balance") Signed-off-by: Chengchang Tang Signed-off-by: Junxian Huang Link: https://lore.kernel.org/r/20230804012711.808069-5-huangjunxian6@hisilicon.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/hns/hns_roce_device.h | 1 + drivers/infiniband/hw/hns/hns_roce_qp.c | 28 ++++++++++++++++----- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 34e099efaae3e..bfe4d84897add 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -97,6 +97,7 @@ #define HNS_ROCE_CQ_BANK_NUM 4 #define CQ_BANKID_SHIFT 2 +#define CQ_BANKID_MASK GENMASK(1, 0) enum { SERV_TYPE_RC, diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index d855a917f4cfa..cdc1c6de43a17 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -170,14 +170,29 @@ static void hns_roce_ib_qp_event(struct hns_roce_qp *hr_qp, } } -static u8 get_least_load_bankid_for_qp(struct hns_roce_bank *bank) +static u8 get_affinity_cq_bank(u8 qp_bank) { - u32 least_load = bank[0].inuse; + return (qp_bank >> 1) & CQ_BANKID_MASK; +} + +static u8 get_least_load_bankid_for_qp(struct ib_qp_init_attr *init_attr, + struct hns_roce_bank *bank) +{ +#define INVALID_LOAD_QPNUM 0xFFFFFFFF + struct ib_cq *scq = init_attr->send_cq; + u32 least_load = INVALID_LOAD_QPNUM; + unsigned long cqn = 0; u8 bankid = 0; u32 bankcnt; u8 i; - for (i = 1; i < HNS_ROCE_QP_BANK_NUM; i++) { + if (scq) + cqn = to_hr_cq(scq)->cqn; + + for (i = 0; i < HNS_ROCE_QP_BANK_NUM; i++) { + if (scq && (get_affinity_cq_bank(i) != (cqn & CQ_BANKID_MASK))) + continue; + bankcnt = bank[i].inuse; if (bankcnt < least_load) { least_load = bankcnt; @@ -209,7 +224,8 @@ static int alloc_qpn_with_bankid(struct hns_roce_bank *bank, u8 bankid, return 0; } -static int alloc_qpn(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp) +static int alloc_qpn(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp, + struct ib_qp_init_attr *init_attr) { struct hns_roce_qp_table *qp_table = &hr_dev->qp_table; unsigned long num = 0; @@ -220,7 +236,7 @@ static int alloc_qpn(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp) num = 1; } else { mutex_lock(&qp_table->bank_mutex); - bankid = get_least_load_bankid_for_qp(qp_table->bank); + bankid = get_least_load_bankid_for_qp(init_attr, qp_table->bank); ret = alloc_qpn_with_bankid(&qp_table->bank[bankid], bankid, &num); @@ -1082,7 +1098,7 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev, goto err_buf; } - ret = alloc_qpn(hr_dev, hr_qp); + ret = alloc_qpn(hr_dev, hr_qp, init_attr); if (ret) { ibdev_err(ibdev, "failed to alloc QPN, ret = %d.\n", ret); goto err_qpn; -- GitLab From 26b7d1a27167e7adf75b150755e05d2bc123ce55 Mon Sep 17 00:00:00 2001 From: Xiang Yang Date: Fri, 4 Aug 2023 10:25:25 +0800 Subject: [PATCH 0852/3445] IB/uverbs: Fix an potential error pointer dereference smatch reports the warning below: drivers/infiniband/core/uverbs_std_types_counters.c:110 ib_uverbs_handler_UVERBS_METHOD_COUNTERS_READ() error: 'uattr' dereferencing possible ERR_PTR() The return value of uattr maybe ERR_PTR(-ENOENT), fix this by checking the value of uattr before using it. Fixes: ebb6796bd397 ("IB/uverbs: Add read counters support") Signed-off-by: Xiang Yang Link: https://lore.kernel.org/r/20230804022525.1916766-1-xiangyang3@huawei.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/core/uverbs_std_types_counters.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/infiniband/core/uverbs_std_types_counters.c b/drivers/infiniband/core/uverbs_std_types_counters.c index 999da9c798668..381aa57976417 100644 --- a/drivers/infiniband/core/uverbs_std_types_counters.c +++ b/drivers/infiniband/core/uverbs_std_types_counters.c @@ -107,6 +107,8 @@ static int UVERBS_HANDLER(UVERBS_METHOD_COUNTERS_READ)( return ret; uattr = uverbs_attr_get(attrs, UVERBS_ATTR_READ_COUNTERS_BUFF); + if (IS_ERR(uattr)) + return PTR_ERR(uattr); read_attr.ncounters = uattr->ptr_attr.len / sizeof(u64); read_attr.counters_buff = uverbs_zalloc( attrs, array_size(read_attr.ncounters, sizeof(u64))); -- GitLab From 849b1955ade1c647234d6fadeb70377d9def01ca Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Fri, 4 Aug 2023 16:21:01 +0800 Subject: [PATCH 0853/3445] RDMA: Remove unnecessary NULL values The NULL initialization of the pointers assigned by kzalloc() first is not necessary, because if the kzalloc() failed, the pointers will be assigned NULL, otherwise it works as usual. so remove it. Signed-off-by: Ruan Jinjie Link: https://lore.kernel.org/r/20230804082102.3361961-1-ruanjinjie@huawei.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/core/iwpm_util.c | 2 +- drivers/infiniband/hw/irdma/verbs.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/core/iwpm_util.c b/drivers/infiniband/core/iwpm_util.c index 358a2db38d232..eecb369898f50 100644 --- a/drivers/infiniband/core/iwpm_util.c +++ b/drivers/infiniband/core/iwpm_util.c @@ -307,7 +307,7 @@ get_remote_info_exit: struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq, u8 nl_client, gfp_t gfp) { - struct iwpm_nlmsg_request *nlmsg_request = NULL; + struct iwpm_nlmsg_request *nlmsg_request; unsigned long flags; nlmsg_request = kzalloc(sizeof(struct iwpm_nlmsg_request), gfp); diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c index 0ca5b88d82e8e..660be7f130600 100644 --- a/drivers/infiniband/hw/irdma/verbs.c +++ b/drivers/infiniband/hw/irdma/verbs.c @@ -2865,8 +2865,8 @@ static struct irdma_mr *irdma_alloc_iwmr(struct ib_umem *region, enum irdma_memreg_type reg_type) { struct irdma_device *iwdev = to_iwdev(pd->device); - struct irdma_pbl *iwpbl = NULL; - struct irdma_mr *iwmr = NULL; + struct irdma_pbl *iwpbl; + struct irdma_mr *iwmr; unsigned long pgsz_bitmap; iwmr = kzalloc(sizeof(*iwmr), GFP_KERNEL); -- GitLab From 4b970e436523ed34da4ced74ad2b81e5a4f573f2 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 1 Aug 2023 21:19:25 +0900 Subject: [PATCH 0854/3445] kbuild: deb-pkg: use Debian compliant shebang for debian/rules Debian Policy "4.9. Main building script: debian/rules" requires "debian/rules must start with the line #!/usr/bin/make -f". [1] Currently, Kbuild does not follow this policy. When Kbuild generates debian/rules, "#!$(command -v $MAKE) -f" is expanded by shell. The resuling string may not be "#!/usr/bin/make -f". There was a reason to opt out the Debian policy. If you run '/path/to/my/custom/make deb-pkg', debian/rules must also be invoked by the same Make program. If #!/usr/bin/make were hard-coded in debian/rules, the sub-make would be executed by a possibly different Make version. This is problematic due to the MAKEFLAGS incompatibility, especially the job server flag. Old Make versions used --jobserver-fds to propagate job server file descriptors, but Make >= 4.2 uses --jobserver-auth. The flag disagreement between the parent/child Makes would result in a process fork explosion. However, having a non-standard path in the shebang causes another issue; the generated source package is not portable as such a path does not exist in other build environments. This commit solves those conflicting demands. Hard-code '#!/usr/bin/make -f' in debian/rules to create a portable and Debian-compliant source package. Pass '--rules-file=$(MAKE) -f debian/rules' when dpkg-buildpackage is invoked from Makefile so that debian/rules is executed by the same Make program as used to start Kbuild. [1] https://www.debian.org/doc/debian-policy/ch-source.html#main-building-script-debian-rules Signed-off-by: Masahiro Yamada Tested-by: Nathan Chancellor Reviewed-by: Nicolas Schier --- scripts/Makefile.package | 2 +- scripts/package/mkdebian | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/Makefile.package b/scripts/Makefile.package index 85beab0363d78..f8a948ec2c6b7 100644 --- a/scripts/Makefile.package +++ b/scripts/Makefile.package @@ -148,7 +148,7 @@ deb-pkg srcdeb-pkg bindeb-pkg: $(if $(findstring source, $(build-type)), \ --unsigned-source --compression=$(KDEB_SOURCE_COMPRESS)) \ $(if $(findstring binary, $(build-type)), \ - -r$(KBUILD_PKG_ROOTCMD) -a$$(cat debian/arch), \ + --rules-file='$(MAKE) -f debian/rules' -r$(KBUILD_PKG_ROOTCMD) -a$$(cat debian/arch), \ --no-check-builddeps) \ $(DPKG_FLAGS)) diff --git a/scripts/package/mkdebian b/scripts/package/mkdebian index 9105abab9728c..2829f5b8aea6f 100755 --- a/scripts/package/mkdebian +++ b/scripts/package/mkdebian @@ -264,7 +264,7 @@ EOF fi cat < debian/rules -#!$(command -v $MAKE) -f +#!/usr/bin/make -f srctree ?= . KERNELRELEASE = ${KERNELRELEASE} -- GitLab From d9287ea8ffc9be2ab4c81c32e1ca54478425ba38 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 1 Aug 2023 21:19:26 +0900 Subject: [PATCH 0855/3445] kbuild: deb-pkg: split debian/rules debian/rules is generated by shell, but the escape sequence (\$) is unreadable. debian/rules embeds only two variables (ARCH and KERNELRELEASE). Split them out to debian/rules.vars, and check-in the rest of Makefile code to scripts/package/debian/rules. Signed-off-by: Masahiro Yamada Tested-by: Nathan Chancellor Reviewed-by: Nicolas Schier --- scripts/package/debian/rules | 28 ++++++++++++++++++++++++++++ scripts/package/mkdebian | 34 +++++----------------------------- 2 files changed, 33 insertions(+), 29 deletions(-) create mode 100755 scripts/package/debian/rules diff --git a/scripts/package/debian/rules b/scripts/package/debian/rules new file mode 100755 index 0000000000000..226e127efd63f --- /dev/null +++ b/scripts/package/debian/rules @@ -0,0 +1,28 @@ +#!/usr/bin/make -f +# SPDX-License-Identifier: GPL-2.0-only + +include debian/rules.vars + +srctree ?= . + +.PHONY: binary binary-indep binary-arch +binary: binary-arch binary-indep +binary-indep: build-indep +binary-arch: build-arch + $(MAKE) -f $(srctree)/Makefile ARCH=$(ARCH) \ + KERNELRELEASE=$(KERNELRELEASE) \ + run-command KBUILD_RUN_COMMAND=+$(srctree)/scripts/package/builddeb + +.PHONY: build build-indep build-arch +build: build-arch build-indep +build-indep: +build-arch: + $(MAKE) -f $(srctree)/Makefile ARCH=$(ARCH) \ + KERNELRELEASE=$(KERNELRELEASE) \ + $(shell $(srctree)/scripts/package/deb-build-option) \ + olddefconfig all + +.PHONY: clean +clean: + rm -rf debian/files debian/linux-* + $(MAKE) -f $(srctree)/Makefile ARCH=$(ARCH) clean diff --git a/scripts/package/mkdebian b/scripts/package/mkdebian index 2829f5b8aea6f..5044224cf6714 100755 --- a/scripts/package/mkdebian +++ b/scripts/package/mkdebian @@ -263,35 +263,11 @@ Description: Linux kernel debugging symbols for $version EOF fi -cat < debian/rules -#!/usr/bin/make -f - -srctree ?= . -KERNELRELEASE = ${KERNELRELEASE} - -.PHONY: clean build build-arch build-indep binary binary-arch binary-indep - -build-indep: -build-arch: - \$(MAKE) -f \$(srctree)/Makefile ARCH=${ARCH} \ - KERNELRELEASE=\$(KERNELRELEASE) \ - \$(shell \$(srctree)/scripts/package/deb-build-option) \ - olddefconfig all - -build: build-arch - -binary-indep: -binary-arch: build-arch - \$(MAKE) -f \$(srctree)/Makefile ARCH=${ARCH} \ - KERNELRELEASE=\$(KERNELRELEASE) \ - run-command KBUILD_RUN_COMMAND=+\$(srctree)/scripts/package/builddeb - -clean: - rm -rf debian/files debian/linux-* - \$(MAKE) -f \$(srctree)/Makefile ARCH=${ARCH} clean - -binary: binary-arch +cat < debian/rules.vars +ARCH := ${ARCH} +KERNELRELEASE := ${KERNELRELEASE} EOF -chmod +x debian/rules + +cp "${srctree}/scripts/package/debian/rules" debian/ exit 0 -- GitLab From 3354c64d418460c500080fddb1171d8e17622a06 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 3 Aug 2023 13:50:20 +0200 Subject: [PATCH 0856/3445] scripts/setlocalversion: clean up stale comment Nobody has complained since 2a73cce2dad3 ("scripts/setlocalversion: remove mercurial, svn and git-svn supports"), so let's also clean up the header comment accordingly. Signed-off-by: Rasmus Villemoes Signed-off-by: Masahiro Yamada --- scripts/setlocalversion | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/setlocalversion b/scripts/setlocalversion index 3d3babac82982..4f1d3eb795e9c 100755 --- a/scripts/setlocalversion +++ b/scripts/setlocalversion @@ -2,7 +2,7 @@ # SPDX-License-Identifier: GPL-2.0 # # This scripts adds local version information from the version -# control systems git, mercurial (hg) and subversion (svn). +# control system git. # # If something goes wrong, send a mail the kernel build mailinglist # (see MAINTAINERS) and CC Nico Schottelius -- GitLab From 01e89a4acefc9d8356e91dde310da11e5b97d22d Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Fri, 4 Aug 2023 14:05:36 +0200 Subject: [PATCH 0857/3445] scripts/setlocalversion: also consider annotated tags of the form vx.y.z-${file_localversion} Commit 6ab7e1f95e96 ("setlocalversion: use only the correct release tag for git-describe") was absolutely correct to limit which annotated tags would be used to compute the -01234-gabcdef suffix. Otherwise, if some random annotated tag exists closer to HEAD than the vX.Y.Z one, the commit count would be too low. However, since the version string always includes the ${file_localversion} part, now the problem is that the count can be too high. For example, building an 6.4.6-rt8 kernel with a few patches on top, I currently get $ make -s kernelrelease 6.4.6-rt8-00128-gd78b7f406397 But those 128 commits include the 100 commits that are in v6.4.6..v6.4.6-rt8, so this is somewhat misleading. Amend the logic so that, in addition to the linux-next consideration, the script also looks for a tag corresponding to the 6.4.6-rt8 part of what will become the `uname -r` string. With this patch (so 29 patches on top of v6.4.6-rt8), one instead gets $ make -s kernelrelease 6.4.6-rt8-00029-gd533209291a2 While there, note that the line git describe --exact-match --match=$tag $tag 2>/dev/null obviously asks if $tag is an annotated tag, but it does not actually tell if the commit pointed to has any relation to HEAD. So remove both uses of --exact-match, and instead just ask if the description generated is identical to the tag we provided. Since we then already have the result of git describe --match=$tag we also end up reducing the number of times we invoke "git describe". Signed-off-by: Rasmus Villemoes Signed-off-by: Masahiro Yamada --- scripts/setlocalversion | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/scripts/setlocalversion b/scripts/setlocalversion index 4f1d3eb795e9c..38b96c6797f40 100755 --- a/scripts/setlocalversion +++ b/scripts/setlocalversion @@ -57,21 +57,37 @@ scm_version() return fi - # If a localversion*' file and the corresponding annotated tag exist, - # use it. This is the case in linux-next. + # mainline kernel: 6.2.0-rc5 -> v6.2-rc5 + # stable kernel: 6.1.7 -> v6.1.7 + version_tag=v$(echo "${KERNELVERSION}" | sed -E 's/^([0-9]+\.[0-9]+)\.0(.*)$/\1\2/') + + # If a localversion* file exists, and the corresponding + # annotated tag exists and is an ancestor of HEAD, use + # it. This is the case in linux-next. tag=${file_localversion#-} - tag=$(git describe --exact-match --match=$tag $tag 2>/dev/null) + desc= + if [ -n "${tag}" ]; then + desc=$(git describe --match=$tag 2>/dev/null) + fi + + # Otherwise, if a localversion* file exists, and the tag + # obtained by appending it to the tag derived from + # KERNELVERSION exists and is an ancestor of HEAD, use + # it. This is e.g. the case in linux-rt. + if [ -z "${desc}" ] && [ -n "${file_localversion}" ]; then + tag="${version_tag}${file_localversion}" + desc=$(git describe --match=$tag 2>/dev/null) + fi # Otherwise, default to the annotated tag derived from KERNELVERSION. - # mainline kernel: 6.2.0-rc5 -> v6.2-rc5 - # stable kernel: 6.1.7 -> v6.1.7 - if [ -z "${tag}" ]; then - tag=v$(echo "${KERNELVERSION}" | sed -E 's/^([0-9]+\.[0-9]+)\.0(.*)$/\1\2/') + if [ -z "${desc}" ]; then + tag="${version_tag}" + desc=$(git describe --match=$tag 2>/dev/null) fi # If we are at the tagged commit, we ignore it because the version is # well-defined. - if [ -z "$(git describe --exact-match --match=$tag 2>/dev/null)" ]; then + if [ "${tag}" != "${desc}" ]; then # If only the short version is requested, don't bother # running further git commands @@ -81,8 +97,8 @@ scm_version() fi # If we are past the tagged commit, we pretty print it. # (like 6.1.0-14595-g292a089d78d3) - if atag="$(git describe --match=$tag 2>/dev/null)"; then - echo "$atag" | awk -F- '{printf("-%05d", $(NF-1))}' + if [ -n "${desc}" ]; then + echo "${desc}" | awk -F- '{printf("-%05d", $(NF-1))}' fi # Add -g and exactly 12 hex chars. -- GitLab From e7e64a1bff12f212be12b048723718c2152c4489 Mon Sep 17 00:00:00 2001 From: Miaohe Lin Date: Mon, 7 Aug 2023 19:58:31 +0800 Subject: [PATCH 0858/3445] cgroup: clean up if condition in cgroup_pidlist_start() There's no need to use '<=' when knowing 'l->list[mid] != pid' already. No functional change intended. Signed-off-by: Miaohe Lin Signed-off-by: Tejun Heo --- kernel/cgroup/cgroup-v1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c index 83044312bc413..c487ffef6652d 100644 --- a/kernel/cgroup/cgroup-v1.c +++ b/kernel/cgroup/cgroup-v1.c @@ -431,7 +431,7 @@ static void *cgroup_pidlist_start(struct seq_file *s, loff_t *pos) if (l->list[mid] == pid) { index = mid; break; - } else if (l->list[mid] <= pid) + } else if (l->list[mid] < pid) index = mid + 1; else end = mid; -- GitLab From 9680540c0c56a1f75a2d6aab31bf38aa429aa9d9 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Fri, 4 Aug 2023 11:22:15 +0800 Subject: [PATCH 0859/3445] workqueue: use LIST_HEAD to initialize cull_list Use LIST_HEAD() to initialize cull_list instead of open-coding it. Signed-off-by: Yang Yingliang Reviewed-by: Lai Jiangshan Signed-off-by: Tejun Heo --- kernel/workqueue.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 83f8993af57cf..a90f1e6425489 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -2304,9 +2304,8 @@ static void idle_worker_timeout(struct timer_list *t) static void idle_cull_fn(struct work_struct *work) { struct worker_pool *pool = container_of(work, struct worker_pool, idle_cull_work); - struct list_head cull_list; + LIST_HEAD(cull_list); - INIT_LIST_HEAD(&cull_list); /* * Grabbing wq_pool_attach_mutex here ensures an already-running worker * cannot proceed beyong worker_detach_from_pool() in its self-destruct @@ -3872,10 +3871,8 @@ static void rcu_free_pool(struct rcu_head *rcu) static void put_unbound_pool(struct worker_pool *pool) { DECLARE_COMPLETION_ONSTACK(detach_completion); - struct list_head cull_list; struct worker *worker; - - INIT_LIST_HEAD(&cull_list); + LIST_HEAD(cull_list); lockdep_assert_held(&wq_pool_mutex); -- GitLab From 0437719c1a97791481c5fd59642494f2108701a8 Mon Sep 17 00:00:00 2001 From: Hao Jia Date: Mon, 7 Aug 2023 11:29:30 +0800 Subject: [PATCH 0860/3445] cgroup/rstat: Record the cumulative per-cpu time of cgroup and its descendants The member variable bstat of the structure cgroup_rstat_cpu records the per-cpu time of the cgroup itself, but does not include the per-cpu time of its descendants. The per-cpu time including descendants is very useful for calculating the per-cpu usage of cgroups. Although we can indirectly obtain the total per-cpu time of the cgroup and its descendants by accumulating the per-cpu bstat of each descendant of the cgroup. But after a child cgroup is removed, we will lose its bstat information. This will cause the cumulative value to be non-monotonic, thus affecting the accuracy of cgroup per-cpu usage. So we add the subtree_bstat variable to record the total per-cpu time of this cgroup and its descendants, which is similar to "cpuacct.usage*" in cgroup v1. And this is also helpful for the migration from cgroup v1 to cgroup v2. After adding this variable, we can obtain the per-cpu time of cgroup and its descendants in user mode through eBPF/drgn, etc. And we are still trying to determine how to expose it in the cgroupfs interface. Suggested-by: Tejun Heo Signed-off-by: Hao Jia Signed-off-by: Tejun Heo --- include/linux/cgroup-defs.h | 14 ++++++++++++++ kernel/cgroup/rstat.c | 12 ++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h index 8a0d5466c7be1..7a2862172f514 100644 --- a/include/linux/cgroup-defs.h +++ b/include/linux/cgroup-defs.h @@ -341,6 +341,20 @@ struct cgroup_rstat_cpu { */ struct cgroup_base_stat last_bstat; + /* + * This field is used to record the cumulative per-cpu time of + * the cgroup and its descendants. Currently it can be read via + * eBPF/drgn etc, and we are still trying to determine how to + * expose it in the cgroupfs interface. + */ + struct cgroup_base_stat subtree_bstat; + + /* + * Snapshots at the last reading. These are used to calculate the + * deltas to propagate to the per-cpu subtree_bstat. + */ + struct cgroup_base_stat last_subtree_bstat; + /* * Child cgroups with stat updates on this cpu since the last read * are linked on the parent's ->updated_children through diff --git a/kernel/cgroup/rstat.c b/kernel/cgroup/rstat.c index 2542c21b6b6d7..d80d7a6081412 100644 --- a/kernel/cgroup/rstat.c +++ b/kernel/cgroup/rstat.c @@ -344,6 +344,7 @@ static void cgroup_base_stat_flush(struct cgroup *cgrp, int cpu) { struct cgroup_rstat_cpu *rstatc = cgroup_rstat_cpu(cgrp, cpu); struct cgroup *parent = cgroup_parent(cgrp); + struct cgroup_rstat_cpu *prstatc; struct cgroup_base_stat delta; unsigned seq; @@ -357,17 +358,24 @@ static void cgroup_base_stat_flush(struct cgroup *cgrp, int cpu) delta = rstatc->bstat; } while (__u64_stats_fetch_retry(&rstatc->bsync, seq)); - /* propagate percpu delta to global */ + /* propagate per-cpu delta to cgroup and per-cpu global statistics */ cgroup_base_stat_sub(&delta, &rstatc->last_bstat); cgroup_base_stat_add(&cgrp->bstat, &delta); cgroup_base_stat_add(&rstatc->last_bstat, &delta); + cgroup_base_stat_add(&rstatc->subtree_bstat, &delta); - /* propagate global delta to parent (unless that's root) */ + /* propagate cgroup and per-cpu global delta to parent (unless that's root) */ if (cgroup_parent(parent)) { delta = cgrp->bstat; cgroup_base_stat_sub(&delta, &cgrp->last_bstat); cgroup_base_stat_add(&parent->bstat, &delta); cgroup_base_stat_add(&cgrp->last_bstat, &delta); + + delta = rstatc->subtree_bstat; + prstatc = cgroup_rstat_cpu(parent, cpu); + cgroup_base_stat_sub(&delta, &rstatc->last_subtree_bstat); + cgroup_base_stat_add(&prstatc->subtree_bstat, &delta); + cgroup_base_stat_add(&rstatc->last_subtree_bstat, &delta); } } -- GitLab From 7bc0153c53bc1ef96e5d1ffb039d9070a944966b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 4 Aug 2023 13:18:38 -0300 Subject: [PATCH 0861/3445] perf probe: Free string returned by synthesize_perf_probe_point() on failure to add a probe Building perf with EXTRA_CFLAGS="-fsanitize=address" a leak is detect when trying to add a probe to a non-existent function: # perf probe -x ~/bin/perf dso__neW Probe point 'dso__neW' not found. Error: Failed to add events. ================================================================= ==296634==ERROR: LeakSanitizer: detected memory leaks Direct leak of 128 byte(s) in 1 object(s) allocated from: #0 0x7f67642ba097 in calloc (/lib64/libasan.so.8+0xba097) #1 0x7f67641a76f1 in allocate_cfi (/lib64/libdw.so.1+0x3f6f1) Direct leak of 65 byte(s) in 1 object(s) allocated from: #0 0x7f67642b95b5 in __interceptor_realloc.part.0 (/lib64/libasan.so.8+0xb95b5) #1 0x6cac75 in strbuf_grow util/strbuf.c:64 #2 0x6ca934 in strbuf_init util/strbuf.c:25 #3 0x9337d2 in synthesize_perf_probe_point util/probe-event.c:2018 #4 0x92be51 in try_to_find_probe_trace_events util/probe-event.c:964 #5 0x93d5c6 in convert_to_probe_trace_events util/probe-event.c:3512 #6 0x93d6d5 in convert_perf_probe_events util/probe-event.c:3529 #7 0x56f37f in perf_add_probe_events /var/home/acme/git/perf-tools-next/tools/perf/builtin-probe.c:354 #8 0x572fbc in __cmd_probe /var/home/acme/git/perf-tools-next/tools/perf/builtin-probe.c:738 #9 0x5730f2 in cmd_probe /var/home/acme/git/perf-tools-next/tools/perf/builtin-probe.c:766 #10 0x635d81 in run_builtin /var/home/acme/git/perf-tools-next/tools/perf/perf.c:323 #11 0x6362c1 in handle_internal_command /var/home/acme/git/perf-tools-next/tools/perf/perf.c:377 #12 0x63667a in run_argv /var/home/acme/git/perf-tools-next/tools/perf/perf.c:421 #13 0x636b8d in main /var/home/acme/git/perf-tools-next/tools/perf/perf.c:537 #14 0x7f676302950f in __libc_start_call_main (/lib64/libc.so.6+0x2950f) SUMMARY: AddressSanitizer: 193 byte(s) leaked in 2 allocation(s). # synthesize_perf_probe_point() returns a "detachec" strbuf, i.e. a malloc'ed string that needs to be free'd. An audit will be performed to find other such cases. Acked-by: Masami Hiramatsu Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/ZM0l1Oxamr4SVjfY@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 2d056f02ae408..c7bfeab610a36 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -961,8 +961,9 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, debuginfo__delete(dinfo); if (ntevs == 0) { /* No error but failed to find probe point. */ - pr_warning("Probe point '%s' not found.\n", - synthesize_perf_probe_point(&pev->point)); + char *probe_point = synthesize_perf_probe_point(&pev->point); + pr_warning("Probe point '%s' not found.\n", probe_point); + free(probe_point); return -ENODEV; } else if (ntevs < 0) { /* Error path : ntevs < 0 */ -- GitLab From a612bbf8b8fdd29136a1ac8b2afca3780278d344 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 4 Aug 2023 13:18:38 -0300 Subject: [PATCH 0862/3445] perf probe: Free string returned by synthesize_perf_probe_point() on failure in synthesize_perf_probe_command() Building perf with EXTRA_CFLAGS="-fsanitize=address" a leak was detected elsewhere and lead to an audit, where we found that synthesize_perf_probe_command() may leak synthesize_perf_probe_point() return on failure, fix it. Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/ZM0mzpQktHnhXJXr@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index c7bfeab610a36..2835d87cb9777 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2063,14 +2063,18 @@ char *synthesize_perf_probe_command(struct perf_probe_event *pev) goto out; tmp = synthesize_perf_probe_point(&pev->point); - if (!tmp || strbuf_addstr(&buf, tmp) < 0) + if (!tmp || strbuf_addstr(&buf, tmp) < 0) { + free(tmp); goto out; + } free(tmp); for (i = 0; i < pev->nargs; i++) { tmp = synthesize_perf_probe_arg(pev->args + i); - if (!tmp || strbuf_addf(&buf, " %s", tmp) < 0) + if (!tmp || strbuf_addf(&buf, " %s", tmp) < 0) { + free(tmp); goto out; + } free(tmp); } -- GitLab From aeb50d3f2cd6255b7d065a91ed6a01784b208e6f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 4 Aug 2023 13:30:06 -0300 Subject: [PATCH 0863/3445] perf probe: Make synthesize_perf_probe_point() private to probe-event.c Not used in any other place, so just make it static. Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/ZM0pjfOe6R4X%2Fcql@kernel.org/ Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 4 +++- tools/perf/util/probe-event.h | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 2835d87cb9777..1a5b7fa459b23 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -53,6 +53,8 @@ bool probe_event_dry_run; /* Dry run flag */ struct probe_conf probe_conf = { .magic_num = DEFAULT_PROBE_MAGIC_NUM }; +static char *synthesize_perf_probe_point(struct perf_probe_point *pp); + #define semantic_error(msg ...) pr_err("Semantic error :" msg) int e_snprintf(char *str, size_t size, const char *format, ...) @@ -2010,7 +2012,7 @@ out: } /* Compose only probe point (not argument) */ -char *synthesize_perf_probe_point(struct perf_probe_point *pp) +static char *synthesize_perf_probe_point(struct perf_probe_point *pp) { struct strbuf buf; char *tmp, *ret = NULL; diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 8ad5b1579f1d3..7e3b6c3d1f744 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -137,7 +137,6 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev); char *synthesize_perf_probe_command(struct perf_probe_event *pev); char *synthesize_probe_trace_command(struct probe_trace_event *tev); char *synthesize_perf_probe_arg(struct perf_probe_arg *pa); -char *synthesize_perf_probe_point(struct perf_probe_point *pp); int perf_probe_event__copy(struct perf_probe_event *dst, struct perf_probe_event *src); -- GitLab From 548fdf771b8e85e6f14fcebcf3443ea475444445 Mon Sep 17 00:00:00 2001 From: Nitin Rawat Date: Wed, 26 Jul 2023 19:11:39 +0530 Subject: [PATCH 0864/3445] scsi: ufs: core: Export ufshcd_is_hba_active() Export ufshcd_is_hba_active() to allow driver modules to check the state of the host controller. Signed-off-by: Nitin Rawat Link: https://lore.kernel.org/r/20230726134140.7180-2-quic_nitirawa@quicinc.com Acked-by: Manivannan Sadhasivam Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 3 ++- include/ufs/ufshcd.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index f45614a840aea..9f43b03f3b728 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -969,10 +969,11 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba) * * Return: true if and only if the controller is active. */ -static inline bool ufshcd_is_hba_active(struct ufs_hba *hba) +bool ufshcd_is_hba_active(struct ufs_hba *hba) { return ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & CONTROLLER_ENABLE; } +EXPORT_SYMBOL_GPL(ufshcd_is_hba_active); u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba) { diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index bf4070a4b95f1..7d07b256e906b 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -1385,6 +1385,7 @@ int ufshcd_wb_toggle_buf_flush(struct ufs_hba *hba, bool enable); int ufshcd_suspend_prepare(struct device *dev); int __ufshcd_suspend_prepare(struct device *dev, bool rpm_ok_for_spm); void ufshcd_resume_complete(struct device *dev); +bool ufshcd_is_hba_active(struct ufs_hba *hba); /* Wrapper functions for safely calling variant operations */ static inline int ufshcd_vops_init(struct ufs_hba *hba) -- GitLab From 21f04fb4e8ca4a6a88c76b1ddf9ea94e6c118005 Mon Sep 17 00:00:00 2001 From: Nitin Rawat Date: Wed, 26 Jul 2023 19:11:40 +0530 Subject: [PATCH 0865/3445] scsi: ufs: ufs-qcom: Check host controller state Commit 52a518019ca1 ("scsi: ufs: core: Fix missing clk change notification on host reset") added UFS clock scaling notification to ufshcd_host_reset_and_restore(). This invokes hibern8 enter and exit on Qualcomm platform which fails because controller is in reset state. Fix this by checking the Host controller state before sending hibern8 command. __ufshcd_wl_resume() ufshcd_reset_and_restore() ufshcd_host_reset_and_restore() ufshcd_scale_clks() ufshcd_vops_clk_scale_notify() ufs_qcom_clk_scale_notify() ufshcd_uic_hibern8_enter() Fixes: 52a518019ca1 ("scsi: ufs: core: Fix missing clk change notification on host reset") Co-developed-by: Manish Pandey Signed-off-by: Manish Pandey Signed-off-by: Nitin Rawat Link: https://lore.kernel.org/r/20230726134140.7180-3-quic_nitirawa@quicinc.com Acked-by: Manivannan Sadhasivam Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index e7164ce7336bd..e894ac548da0a 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1382,6 +1382,10 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, struct ufs_pa_layer_attr *dev_req_params = &host->dev_req_params; int err = 0; + /* check the host controller state before sending hibern8 cmd */ + if (!ufshcd_is_hba_active(hba)) + return 0; + if (status == PRE_CHANGE) { err = ufshcd_uic_hibern8_enter(hba); if (err) -- GitLab From c306f746fee55b07d92dc768f3167f5b27a677db Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 1 Aug 2023 16:21:50 -0700 Subject: [PATCH 0866/3445] scsi: ufs: core: Fix the build for gcc 9 and before gcc compilers before version 10 cannot do constant-folding for sub-byte bitfields. This makes the compiler layout tests fail. Hence skip the layout checks for gcc 9 and before. Cc: Arnd Bergmann Cc: Naresh Kamboju Cc: Nathan Chancellor Reported-by: Naresh Kamboju Closes: https://lore.kernel.org/linux-scsi/CA+G9fYur8UJoUyTLJFVEJPh-15TJ7kbdD2q8xVz8a3fLjkxxVw@mail.gmail.com/ Suggested-by: Arnd Bergmann Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20230801232204.1481902-1-bvanassche@acm.org Tested-by: Arnd Bergmann Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 9f43b03f3b728..8b5ee1a7d454c 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -10527,6 +10527,14 @@ static const struct dev_pm_ops ufshcd_wl_pm_ops = { static void ufshcd_check_header_layout(void) { + /* + * gcc compilers before version 10 cannot do constant-folding for + * sub-byte bitfields. Hence skip the layout checks for gcc 9 and + * before. + */ + if (IS_ENABLED(CONFIG_CC_IS_GCC) && CONFIG_GCC_VERSION < 100000) + return; + BUILD_BUG_ON(((u8 *)&(struct request_desc_header){ .cci = 3})[0] != 3); -- GitLab From 01e747157b6143b62240cebcc4493f9eaad12a08 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 2 Aug 2023 09:31:54 +0530 Subject: [PATCH 0867/3445] scsi: ufs: qcom: Make struct ufs_qcom_bw_table static const ufs_qcom_bw_table is not modified anywhere. So make it static const so that it can be placed in read-only memory. Reported-by: Bart Van Assche Closes: https://lore.kernel.org/linux-scsi/43cd0057-c6d8-bc92-08f4-d767336d2cfe@acm.org/ Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20230802040154.10652-1-manivannan.sadhasivam@linaro.org Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index e894ac548da0a..f88febb231230 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -58,7 +58,7 @@ enum { MODE_MAX, }; -struct __ufs_qcom_bw_table { +static const struct __ufs_qcom_bw_table { u32 mem_bw; u32 cfg_bw; } ufs_qcom_bw_table[MODE_MAX + 1][QCOM_UFS_MAX_GEAR + 1][QCOM_UFS_MAX_LANE + 1] = { -- GitLab From dded1dc31aa433ab4442dbe8e5a14d2a9a919bcd Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Fri, 4 Aug 2023 12:55:46 -0700 Subject: [PATCH 0868/3445] scsi: lpfc: Modify when a node should be put in device recovery mode during RSCN Only nodes whose state is at least past a PLOGI issue and strictly less than a PRLI issue should be put into device recovery mode upon RSCN receipt. Previously, the allowance of LOGO and PRLI completion states did not make sense because those nodes should be allowed to flow through and marked as NPort dissappeared as is normally done. A follow up RSCN GID_FT would recover those nodes in such cases. Signed-off-by: Justin Tee Link: https://lore.kernel.org/r/20230804195546.157839-1-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hbadisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 388a481c81182..467c255bbe4c3 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -5782,7 +5782,7 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) return NULL; if (ndlp->nlp_state > NLP_STE_UNUSED_NODE && - ndlp->nlp_state < NLP_STE_NPR_NODE) { + ndlp->nlp_state < NLP_STE_PRLI_ISSUE) { lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RECOVERY); } -- GitLab From 9134211f7bed218bc01940fc24ebe8b4bc02b69b Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Fri, 4 Aug 2023 16:12:43 +0530 Subject: [PATCH 0869/3445] scsi: mpi3mr: Invoke soft reset upon TSU or event ack time out When a timestamp update or an event acknowledgment command times out, the driver invokes the soft reset handler to recover the controller while holding a mutex lock. The soft reset handler also tries to acquire the same mutex to send initialization commands to the controller which leads to a deadlock scenario. To resolve the issue the driver will check thestatus and if this indicates the controller is operational, the driver will issue a diagnostic fault reset and exit out of the command processing function. If the controller is already faulted or asynchronously reset, then the driver will just exit the command processing function. Signed-off-by: Ranjan Kumar Link: https://lore.kernel.org/r/20230804104248.118924-2-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_fw.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 5fa07d6ee5b8e..11b78d4a87a0b 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -2343,8 +2343,8 @@ static int mpi3mr_sync_timestamp(struct mpi3mr_ioc *mrioc) ioc_err(mrioc, "Issue IOUCTL time_stamp: command timed out\n"); mrioc->init_cmds.is_waiting = 0; if (!(mrioc->init_cmds.state & MPI3MR_CMD_RESET)) - mpi3mr_soft_reset_handler(mrioc, - MPI3MR_RESET_FROM_TSU_TIMEOUT, 1); + mpi3mr_check_rh_fault_ioc(mrioc, + MPI3MR_RESET_FROM_TSU_TIMEOUT); retval = -1; goto out_unlock; } @@ -3359,8 +3359,8 @@ int mpi3mr_process_event_ack(struct mpi3mr_ioc *mrioc, u8 event, if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { ioc_err(mrioc, "Issue EvtNotify: command timed out\n"); if (!(mrioc->init_cmds.state & MPI3MR_CMD_RESET)) - mpi3mr_soft_reset_handler(mrioc, - MPI3MR_RESET_FROM_EVTACK_TIMEOUT, 1); + mpi3mr_check_rh_fault_ioc(mrioc, + MPI3MR_RESET_FROM_EVTACK_TIMEOUT); retval = -1; goto out_unlock; } -- GitLab From 6f81b1cfdf33533925dbbfab9923f67fb4a31858 Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Fri, 4 Aug 2023 16:12:44 +0530 Subject: [PATCH 0870/3445] scsi: mpi3mr: Update MPI Headers to version 3.00.28 Updated MPI Headers to version 3.00.28. Signed-off-by: Ranjan Kumar Link: https://lore.kernel.org/r/20230804104248.118924-3-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h | 2 +- drivers/scsi/mpi3mr/mpi/mpi30_ioc.h | 1 + drivers/scsi/mpi3mr/mpi/mpi30_transport.h | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h index 2fc196499c892..35f81af40f511 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h @@ -1482,7 +1482,7 @@ struct mpi3_security_page0 { #define MPI3_SECURITY1_KEY_RECORD_MAX 1 #endif #ifndef MPI3_SECURITY1_PAD_MAX -#define MPI3_SECURITY1_PAD_MAX 1 +#define MPI3_SECURITY1_PAD_MAX 4 #endif union mpi3_security1_key_data { __le32 dword[128]; diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h index f5e9c2309ce6d..1e4a60fc655f8 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h @@ -600,6 +600,7 @@ struct mpi3_event_data_pcie_error_threshold { __le16 threshold_count; __le16 attached_dev_handle; __le16 reserved12; + __le32 reserved14; }; #define MPI3_EVENT_PCI_ERROR_RC_THRESHOLD_EXCEEDED (0x00) diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_transport.h b/drivers/scsi/mpi3mr/mpi/mpi30_transport.h index 441cfc2c7f095..1e0a3dcaf7232 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_transport.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_transport.h @@ -18,7 +18,7 @@ union mpi3_version_union { #define MPI3_VERSION_MAJOR (3) #define MPI3_VERSION_MINOR (0) -#define MPI3_VERSION_UNIT (27) +#define MPI3_VERSION_UNIT (28) #define MPI3_VERSION_DEV (0) #define MPI3_DEVHANDLE_INVALID (0xffff) struct mpi3_sysif_oper_queue_indexes { -- GitLab From d9adb81e67e9be51990a14389cd1762086b44985 Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Fri, 4 Aug 2023 16:12:45 +0530 Subject: [PATCH 0871/3445] scsi: mpi3mr: Add support for more than 1MB I/O Enhance the driver to get the maximum data length per I/O request from IOC Facts data and report that to the upper layers. If the IOC facts data is not reported then a default I/O size of 1MB is reported to the OS. Signed-off-by: Ranjan Kumar Link: https://lore.kernel.org/r/20230804104248.118924-4-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 8 ++++++-- drivers/scsi/mpi3mr/mpi3mr_fw.c | 29 ++++++++++++++++++++++++----- drivers/scsi/mpi3mr/mpi3mr_os.c | 24 ++++++++++++++++++++---- 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 0afb687402e15..fd3619775739d 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -66,11 +66,12 @@ extern atomic64_t event_counter; #define MPI3MR_NAME_LENGTH 32 #define IOCNAME "%s: " -#define MPI3MR_MAX_SECTORS 2048 +#define MPI3MR_DEFAULT_MAX_IO_SIZE (1 * 1024 * 1024) /* Definitions for internal SGL and Chain SGL buffers */ #define MPI3MR_PAGE_SIZE_4K 4096 -#define MPI3MR_SG_DEPTH (MPI3MR_PAGE_SIZE_4K / sizeof(struct mpi3_sge_common)) +#define MPI3MR_DEFAULT_SGL_ENTRIES 256 +#define MPI3MR_MAX_SGL_ENTRIES 2048 /* Definitions for MAX values for shost */ #define MPI3MR_MAX_CMDS_LUN 128 @@ -323,6 +324,7 @@ struct mpi3mr_ioc_facts { u16 max_perids; u16 max_pds; u16 max_sasexpanders; + u32 max_data_length; u16 max_sasinitiators; u16 max_enclosures; u16 max_pcie_switches; @@ -959,6 +961,7 @@ struct scmd_priv { * @stop_drv_processing: Stop all command processing * @device_refresh_on: Don't process the events until devices are refreshed * @max_host_ios: Maximum host I/O count + * @max_sgl_entries: Max SGL entries per I/O * @chain_buf_count: Chain buffer count * @chain_buf_pool: Chain buffer pool * @chain_sgl_list: Chain SGL list @@ -1129,6 +1132,7 @@ struct mpi3mr_ioc { u16 max_host_ios; spinlock_t tgtdev_lock; struct list_head tgtdev_list; + u16 max_sgl_entries; u32 chain_buf_count; struct dma_pool *chain_buf_pool; diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 11b78d4a87a0b..f039f1d986477 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -1163,6 +1163,12 @@ mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc) return -EPERM; } + if (mrioc->shost->max_sectors != (mrioc->facts.max_data_length / 512)) + ioc_err(mrioc, "Warning: The maximum data transfer length\n" + "\tchanged after reset: previous(%d), new(%d),\n" + "the driver cannot change this at run time\n", + mrioc->shost->max_sectors * 512, mrioc->facts.max_data_length); + if ((mrioc->sas_transport_enabled) && (mrioc->facts.ioc_capabilities & MPI3_IOCFACTS_CAPABILITY_MULTIPATH_ENABLED)) ioc_err(mrioc, @@ -2856,6 +2862,7 @@ static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, le16_to_cpu(facts_data->max_pcie_switches); mrioc->facts.max_sasexpanders = le16_to_cpu(facts_data->max_sas_expanders); + mrioc->facts.max_data_length = le16_to_cpu(facts_data->max_data_length); mrioc->facts.max_sasinitiators = le16_to_cpu(facts_data->max_sas_initiators); mrioc->facts.max_enclosures = le16_to_cpu(facts_data->max_enclosures); @@ -2893,13 +2900,18 @@ static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, mrioc->facts.io_throttle_high = le16_to_cpu(facts_data->io_throttle_high); + if (mrioc->facts.max_data_length == + MPI3_IOCFACTS_MAX_DATA_LENGTH_NOT_REPORTED) + mrioc->facts.max_data_length = MPI3MR_DEFAULT_MAX_IO_SIZE; + else + mrioc->facts.max_data_length *= MPI3MR_PAGE_SIZE_4K; /* Store in 512b block count */ if (mrioc->facts.io_throttle_data_length) mrioc->io_throttle_data_length = (mrioc->facts.io_throttle_data_length * 2 * 4); else /* set the length to 1MB + 1K to disable throttle */ - mrioc->io_throttle_data_length = MPI3MR_MAX_SECTORS + 2; + mrioc->io_throttle_data_length = (mrioc->facts.max_data_length / 512) + 2; mrioc->io_throttle_high = (mrioc->facts.io_throttle_high * 2 * 1024); mrioc->io_throttle_low = (mrioc->facts.io_throttle_low * 2 * 1024); @@ -2914,9 +2926,9 @@ static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, ioc_info(mrioc, "SGEModMask 0x%x SGEModVal 0x%x SGEModShift 0x%x ", mrioc->facts.sge_mod_mask, mrioc->facts.sge_mod_value, mrioc->facts.sge_mod_shift); - ioc_info(mrioc, "DMA mask %d InitialPE status 0x%x\n", + ioc_info(mrioc, "DMA mask %d InitialPE status 0x%x max_data_len (%d)\n", mrioc->facts.dma_mask, (facts_flags & - MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK)); + MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK), mrioc->facts.max_data_length); ioc_info(mrioc, "max_dev_per_throttle_group(%d), max_throttle_groups(%d)\n", mrioc->facts.max_dev_per_tg, mrioc->facts.max_io_throttle_group); @@ -3414,7 +3426,14 @@ static int mpi3mr_alloc_chain_bufs(struct mpi3mr_ioc *mrioc) if (!mrioc->chain_sgl_list) goto out_failed; - sz = MPI3MR_PAGE_SIZE_4K; + if (mrioc->max_sgl_entries > (mrioc->facts.max_data_length / + MPI3MR_PAGE_SIZE_4K)) + mrioc->max_sgl_entries = mrioc->facts.max_data_length / + MPI3MR_PAGE_SIZE_4K; + sz = mrioc->max_sgl_entries * sizeof(struct mpi3_sge_common); + ioc_info(mrioc, "number of sgl entries=%d chain buffer size=%dKB\n", + mrioc->max_sgl_entries, sz/1024); + mrioc->chain_buf_pool = dma_pool_create("chain_buf pool", &mrioc->pdev->dev, sz, 16, 0); if (!mrioc->chain_buf_pool) { @@ -3813,7 +3832,7 @@ retry_init: } mrioc->max_host_ios = mrioc->facts.max_reqs - MPI3MR_INTERNAL_CMDS_RESVD; - + mrioc->shost->max_sectors = mrioc->facts.max_data_length / 512; mrioc->num_io_throttle_group = mrioc->facts.max_io_throttle_group; atomic_set(&mrioc->pend_large_data_sz, 0); diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index d627355303d79..b19b624d0e970 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -33,6 +33,12 @@ static int logging_level; module_param(logging_level, int, 0); MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info (default=0)"); +static int max_sgl_entries = MPI3MR_DEFAULT_SGL_ENTRIES; +module_param(max_sgl_entries, int, 0444); +MODULE_PARM_DESC(max_sgl_entries, + "Preferred max number of SG entries to be used for a single I/O\n" + "The actual value will be determined by the driver\n" + "(Minimum=256, Maximum=2048, default=256)"); /* Forward declarations*/ static void mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event, @@ -3413,7 +3419,7 @@ static int mpi3mr_prepare_sg_scmd(struct mpi3mr_ioc *mrioc, scsi_bufflen(scmd)); return -ENOMEM; } - if (sges_left > MPI3MR_SG_DEPTH) { + if (sges_left > mrioc->max_sgl_entries) { sdev_printk(KERN_ERR, scmd->device, "scsi_dma_map returned unsupported sge count %d!\n", sges_left); @@ -4818,10 +4824,10 @@ static const struct scsi_host_template mpi3mr_driver_template = { .no_write_same = 1, .can_queue = 1, .this_id = -1, - .sg_tablesize = MPI3MR_SG_DEPTH, + .sg_tablesize = MPI3MR_DEFAULT_SGL_ENTRIES, /* max xfer supported is 1M (2K in 512 byte sized sectors) */ - .max_sectors = 2048, + .max_sectors = (MPI3MR_DEFAULT_MAX_IO_SIZE / 512), .cmd_per_lun = MPI3MR_MAX_CMDS_LUN, .max_segment_size = 0xffffffff, .track_queue_depth = 1, @@ -5004,6 +5010,16 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id) mrioc->pdev = pdev; mrioc->stop_bsgs = 1; + mrioc->max_sgl_entries = max_sgl_entries; + if (max_sgl_entries > MPI3MR_MAX_SGL_ENTRIES) + mrioc->max_sgl_entries = MPI3MR_MAX_SGL_ENTRIES; + else if (max_sgl_entries < MPI3MR_DEFAULT_SGL_ENTRIES) + mrioc->max_sgl_entries = MPI3MR_DEFAULT_SGL_ENTRIES; + else { + mrioc->max_sgl_entries /= MPI3MR_DEFAULT_SGL_ENTRIES; + mrioc->max_sgl_entries *= MPI3MR_DEFAULT_SGL_ENTRIES; + } + /* init shost parameters */ shost->max_cmd_len = MPI3MR_MAX_CDB_LENGTH; shost->max_lun = -1; @@ -5068,7 +5084,7 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id) shost->nr_maps = 3; shost->can_queue = mrioc->max_host_ios; - shost->sg_tablesize = MPI3MR_SG_DEPTH; + shost->sg_tablesize = mrioc->max_sgl_entries; shost->max_id = mrioc->facts.max_perids + 1; retval = scsi_add_host(shost, &pdev->dev); -- GitLab From e7a8648e1ce2ddbc74ac69da83dcebbee0c7e1b8 Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Fri, 4 Aug 2023 16:12:46 +0530 Subject: [PATCH 0872/3445] scsi: mpi3mr: WRITE SAME implementation Enhance driver to divert the WRITE SAME commands that are issued with UNMAP=1 and NDOB=1 and with the transfer length greater than the max WRITE SAME length specified by the firmware for the particular drive to the controller firmware. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202307280034.DXU5pTVV-lkp@intel.com/ Signed-off-by: Ranjan Kumar Link: https://lore.kernel.org/r/20230804104248.118924-5-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 11 +++ drivers/scsi/mpi3mr/mpi3mr_os.c | 118 +++++++++++++++++++++++++------- 2 files changed, 105 insertions(+), 24 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index fd3619775739d..8b009ba26d882 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -207,6 +207,9 @@ extern atomic64_t event_counter; */ #define MPI3MR_MAX_APP_XFER_SECTORS (2048 + 512) +#define MPI3MR_WRITE_SAME_MAX_LEN_256_BLKS 256 +#define MPI3MR_WRITE_SAME_MAX_LEN_2048_BLKS 2048 + /** * struct mpi3mr_nvme_pt_sge - Structure to store SGEs for NVMe * Encapsulated commands. @@ -678,6 +681,7 @@ enum mpi3mr_dev_state { * @io_unit_port: IO Unit port ID * @non_stl: Is this device not to be attached with SAS TL * @io_throttle_enabled: I/O throttling needed or not + * @wslen: Write same max length * @q_depth: Device specific Queue Depth * @wwid: World wide ID * @enclosure_logical_id: Enclosure logical identifier @@ -700,6 +704,7 @@ struct mpi3mr_tgt_dev { u8 io_unit_port; u8 non_stl; u8 io_throttle_enabled; + u16 wslen; u16 q_depth; u64 wwid; u64 enclosure_logical_id; @@ -753,6 +758,8 @@ static inline void mpi3mr_tgtdev_put(struct mpi3mr_tgt_dev *s) * @dev_removed: Device removed in the Firmware * @dev_removedelay: Device is waiting to be removed in FW * @dev_type: Device type + * @dev_nvme_dif: Device is NVMe DIF enabled + * @wslen: Write same max length * @io_throttle_enabled: I/O throttling needed or not * @io_divert: Flag indicates io divert is on or off for the dev * @throttle_group: Pointer to throttle group info @@ -769,6 +776,8 @@ struct mpi3mr_stgt_priv_data { u8 dev_removed; u8 dev_removedelay; u8 dev_type; + u8 dev_nvme_dif; + u16 wslen; u8 io_throttle_enabled; u8 io_divert; struct mpi3mr_throttle_group_info *throttle_group; @@ -784,12 +793,14 @@ struct mpi3mr_stgt_priv_data { * @ncq_prio_enable: NCQ priority enable for SATA device * @pend_count: Counter to track pending I/Os during error * handling + * @wslen: Write same max length */ struct mpi3mr_sdev_priv_data { struct mpi3mr_stgt_priv_data *tgt_priv_data; u32 lun_id; u8 ncq_prio_enable; u32 pend_count; + u16 wslen; }; /** diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index b19b624d0e970..fcf0888232e71 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -430,6 +430,7 @@ void mpi3mr_invalidate_devhandles(struct mpi3mr_ioc *mrioc) tgt_priv->io_throttle_enabled = 0; tgt_priv->io_divert = 0; tgt_priv->throttle_group = NULL; + tgt_priv->wslen = 0; if (tgtdev->host_exposed) atomic_set(&tgt_priv->block_io, 1); } @@ -1108,6 +1109,18 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, tgtdev->io_throttle_enabled = (flags & MPI3_DEVICE0_FLAGS_IO_THROTTLING_REQUIRED) ? 1 : 0; + switch (flags & MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_MASK) { + case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_256_LB: + tgtdev->wslen = MPI3MR_WRITE_SAME_MAX_LEN_256_BLKS; + break; + case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_2048_LB: + tgtdev->wslen = MPI3MR_WRITE_SAME_MAX_LEN_2048_BLKS; + break; + case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_NO_LIMIT: + default: + tgtdev->wslen = 0; + break; + } if (tgtdev->starget && tgtdev->starget->hostdata) { scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *) @@ -1119,6 +1132,7 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, tgtdev->io_throttle_enabled; if (is_added == true) atomic_set(&scsi_tgt_priv_data->block_io, 0); + scsi_tgt_priv_data->wslen = tgtdev->wslen; } switch (dev_pg0->access_status) { @@ -3939,6 +3953,48 @@ void mpi3mr_wait_for_host_io(struct mpi3mr_ioc *mrioc, u32 timeout) mpi3mr_get_fw_pending_ios(mrioc)); } +/** + * mpi3mr_setup_divert_ws - Setup Divert IO flag for write same + * @mrioc: Adapter instance reference + * @scmd: SCSI command reference + * @scsiio_req: MPI3 SCSI IO request + * @scsiio_flags: Pointer to MPI3 SCSI IO Flags + * @wslen: write same max length + * + * Gets values of unmap, ndob and number of blocks from write + * same scsi io and based on these values it sets divert IO flag + * and reason for diverting IO to firmware. + * + * Return: Nothing + */ +static inline void mpi3mr_setup_divert_ws(struct mpi3mr_ioc *mrioc, + struct scsi_cmnd *scmd, struct mpi3_scsi_io_request *scsiio_req, + u32 *scsiio_flags, u16 wslen) +{ + u8 unmap = 0, ndob = 0; + u8 opcode = scmd->cmnd[0]; + u32 num_blocks = 0; + u16 sa = (scmd->cmnd[8] << 8) | (scmd->cmnd[9]); + + if (opcode == WRITE_SAME_16) { + unmap = scmd->cmnd[1] & 0x08; + ndob = scmd->cmnd[1] & 0x01; + num_blocks = get_unaligned_be32(scmd->cmnd + 10); + } else if ((opcode == VARIABLE_LENGTH_CMD) && (sa == WRITE_SAME_32)) { + unmap = scmd->cmnd[10] & 0x08; + ndob = scmd->cmnd[10] & 0x01; + num_blocks = get_unaligned_be32(scmd->cmnd + 28); + } else + return; + + if ((unmap) && (ndob) && (num_blocks > wslen)) { + scsiio_req->msg_flags |= + MPI3_SCSIIO_MSGFLAGS_DIVERT_TO_FIRMWARE; + *scsiio_flags |= + MPI3_SCSIIO_FLAGS_DIVERT_REASON_WRITE_SAME_TOO_LARGE; + } +} + /** * mpi3mr_eh_host_reset - Host reset error handling callback * @scmd: SCSI command reference @@ -4436,7 +4492,6 @@ static int mpi3mr_target_alloc(struct scsi_target *starget) unsigned long flags; int retval = 0; struct sas_rphy *rphy = NULL; - bool update_stgt_priv_data = false; scsi_tgt_priv_data = kzalloc(sizeof(*scsi_tgt_priv_data), GFP_KERNEL); if (!scsi_tgt_priv_data) @@ -4445,39 +4500,50 @@ static int mpi3mr_target_alloc(struct scsi_target *starget) starget->hostdata = scsi_tgt_priv_data; spin_lock_irqsave(&mrioc->tgtdev_lock, flags); - if (starget->channel == mrioc->scsi_device_channel) { tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id); - if (tgt_dev && !tgt_dev->is_hidden) - update_stgt_priv_data = true; - else + if (tgt_dev && !tgt_dev->is_hidden) { + scsi_tgt_priv_data->starget = starget; + scsi_tgt_priv_data->dev_handle = tgt_dev->dev_handle; + scsi_tgt_priv_data->perst_id = tgt_dev->perst_id; + scsi_tgt_priv_data->dev_type = tgt_dev->dev_type; + scsi_tgt_priv_data->tgt_dev = tgt_dev; + tgt_dev->starget = starget; + atomic_set(&scsi_tgt_priv_data->block_io, 0); + retval = 0; + if ((tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_PCIE) && + ((tgt_dev->dev_spec.pcie_inf.dev_info & + MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) == + MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) && + ((tgt_dev->dev_spec.pcie_inf.dev_info & + MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_MASK) != + MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_0)) + scsi_tgt_priv_data->dev_nvme_dif = 1; + scsi_tgt_priv_data->io_throttle_enabled = tgt_dev->io_throttle_enabled; + scsi_tgt_priv_data->wslen = tgt_dev->wslen; + if (tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_VD) + scsi_tgt_priv_data->throttle_group = tgt_dev->dev_spec.vd_inf.tg; + } else retval = -ENXIO; } else if (mrioc->sas_transport_enabled && !starget->channel) { rphy = dev_to_rphy(starget->dev.parent); tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc, rphy->identify.sas_address, rphy); if (tgt_dev && !tgt_dev->is_hidden && !tgt_dev->non_stl && - (tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_SAS_SATA)) - update_stgt_priv_data = true; - else + (tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_SAS_SATA)) { + scsi_tgt_priv_data->starget = starget; + scsi_tgt_priv_data->dev_handle = tgt_dev->dev_handle; + scsi_tgt_priv_data->perst_id = tgt_dev->perst_id; + scsi_tgt_priv_data->dev_type = tgt_dev->dev_type; + scsi_tgt_priv_data->tgt_dev = tgt_dev; + scsi_tgt_priv_data->io_throttle_enabled = tgt_dev->io_throttle_enabled; + scsi_tgt_priv_data->wslen = tgt_dev->wslen; + tgt_dev->starget = starget; + atomic_set(&scsi_tgt_priv_data->block_io, 0); + retval = 0; + } else retval = -ENXIO; } - - if (update_stgt_priv_data) { - scsi_tgt_priv_data->starget = starget; - scsi_tgt_priv_data->dev_handle = tgt_dev->dev_handle; - scsi_tgt_priv_data->perst_id = tgt_dev->perst_id; - scsi_tgt_priv_data->dev_type = tgt_dev->dev_type; - scsi_tgt_priv_data->tgt_dev = tgt_dev; - tgt_dev->starget = starget; - atomic_set(&scsi_tgt_priv_data->block_io, 0); - retval = 0; - scsi_tgt_priv_data->io_throttle_enabled = - tgt_dev->io_throttle_enabled; - if (tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_VD) - scsi_tgt_priv_data->throttle_group = - tgt_dev->dev_spec.vd_inf.tg; - } spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); return retval; @@ -4738,6 +4804,10 @@ static int mpi3mr_qcmd(struct Scsi_Host *shost, mpi3mr_setup_eedp(mrioc, scmd, scsiio_req); + if (stgt_priv_data->wslen) + mpi3mr_setup_divert_ws(mrioc, scmd, scsiio_req, &scsiio_flags, + stgt_priv_data->wslen); + memcpy(scsiio_req->cdb.cdb32, scmd->cmnd, scmd->cmd_len); scsiio_req->data_length = cpu_to_le32(scsi_bufflen(scmd)); scsiio_req->dev_handle = cpu_to_le16(dev_handle); -- GitLab From d9a5ab0ea98fdee77fcbfec27bb3976de9615377 Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Fri, 4 Aug 2023 16:12:47 +0530 Subject: [PATCH 0873/3445] scsi: mpi3mr: Enhance handling of devices removed after controller reset Mark all of the devices that are exposed to the OS prior to a controller reset and not detected by the controller after the reset as removed devices and the I/Os to those devices are unblocked (and returned with DID_NO_CONNECT) prior to removing the devices one after the other. Signed-off-by: Ranjan Kumar Link: https://lore.kernel.org/r/20230804104248.118924-6-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_os.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index fcf0888232e71..89ba015c5d7e8 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -1041,6 +1041,19 @@ mpi3mr_update_sdev(struct scsi_device *sdev, void *data) void mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc *mrioc) { struct mpi3mr_tgt_dev *tgtdev, *tgtdev_next; + struct mpi3mr_stgt_priv_data *tgt_priv; + + dprint_reset(mrioc, "refresh target devices: check for removals\n"); + list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list, + list) { + if ((tgtdev->dev_handle == MPI3MR_INVALID_DEV_HANDLE) && + tgtdev->host_exposed && tgtdev->starget && + tgtdev->starget->hostdata) { + tgt_priv = tgtdev->starget->hostdata; + tgt_priv->dev_removed = 1; + atomic_set(&tgt_priv->block_io, 0); + } + } list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list, list) { -- GitLab From 9a9068b2afa0b0bf559b66b374785d2fcb5b9b5e Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Fri, 4 Aug 2023 16:12:48 +0530 Subject: [PATCH 0874/3445] scsi: mpi3mr: Update driver version to 8.5.0.0.0 Update driver version to 8.5.0.0.0 Signed-off-by: Ranjan Kumar Link: https://lore.kernel.org/r/20230804104248.118924-7-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 8b009ba26d882..ae98d15c30b1d 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -55,8 +55,8 @@ extern struct list_head mrioc_list; extern int prot_mask; extern atomic64_t event_counter; -#define MPI3MR_DRIVER_VERSION "8.4.1.0.0" -#define MPI3MR_DRIVER_RELDATE "16-March-2023" +#define MPI3MR_DRIVER_VERSION "8.5.0.0.0" +#define MPI3MR_DRIVER_RELDATE "24-July-2023" #define MPI3MR_DRIVER_NAME "mpi3mr" #define MPI3MR_DRIVER_LICENSE "GPL" -- GitLab From bc8b50c2dfac946c1beed782c1823e52cf55a352 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:22 -1000 Subject: [PATCH 0875/3445] workqueue: Drop the special locking rule for worker->flags and worker_pool->flags worker->flags used to be accessed from scheduler hooks without grabbing pool->lock for concurrency management. This is no longer true since 6d25be5782e4 ("sched/core, workqueues: Distangle worker accounting from rq lock"). Also, it's unclear why worker_pool->flags was using the "X" rule. All relevant users are accessing it under the pool lock. Let's drop the special "X" rule and use the "L" rule for these flag fields instead. While at it, replace the CONTEXT comment with lockdep_assert_held(). This allows worker_set/clr_flags() to be used from context which isn't the worker itself. This will be used later to implement assinging work items to workers before waking them up so that workqueue can have better control over which worker executes which work item on which CPU. The only actual changes are sanity checks. There shouldn't be any visible behavior changes. Signed-off-by: Tejun Heo --- kernel/workqueue.c | 17 +++-------------- kernel/workqueue_internal.h | 2 +- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index ae975a7c9f698..598009ad97d1a 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -122,11 +122,6 @@ enum { * * L: pool->lock protected. Access with pool->lock held. * - * X: During normal operation, modification requires pool->lock and should - * be done only from local cpu. Either disabling preemption on local - * cpu or grabbing pool->lock is enough for read access. If - * POOL_DISASSOCIATED is set, it's identical to L. - * * K: Only modified by worker while holding pool->lock. Can be safely read by * self, while holding pool->lock or from IRQ context if %current is the * kworker. @@ -160,7 +155,7 @@ struct worker_pool { int cpu; /* I: the associated cpu */ int node; /* I: the associated node ID */ int id; /* I: pool ID */ - unsigned int flags; /* X: flags */ + unsigned int flags; /* L: flags */ unsigned long watchdog_ts; /* L: watchdog timestamp */ bool cpu_stall; /* WD: stalled cpu bound pool */ @@ -910,15 +905,12 @@ static void wake_up_worker(struct worker_pool *pool) * @flags: flags to set * * Set @flags in @worker->flags and adjust nr_running accordingly. - * - * CONTEXT: - * raw_spin_lock_irq(pool->lock) */ static inline void worker_set_flags(struct worker *worker, unsigned int flags) { struct worker_pool *pool = worker->pool; - WARN_ON_ONCE(worker->task != current); + lockdep_assert_held(&pool->lock); /* If transitioning into NOT_RUNNING, adjust nr_running. */ if ((flags & WORKER_NOT_RUNNING) && @@ -935,16 +927,13 @@ static inline void worker_set_flags(struct worker *worker, unsigned int flags) * @flags: flags to clear * * Clear @flags in @worker->flags and adjust nr_running accordingly. - * - * CONTEXT: - * raw_spin_lock_irq(pool->lock) */ static inline void worker_clr_flags(struct worker *worker, unsigned int flags) { struct worker_pool *pool = worker->pool; unsigned int oflags = worker->flags; - WARN_ON_ONCE(worker->task != current); + lockdep_assert_held(&pool->lock); worker->flags &= ~flags; diff --git a/kernel/workqueue_internal.h b/kernel/workqueue_internal.h index 6b1d66e282696..f6275944ada77 100644 --- a/kernel/workqueue_internal.h +++ b/kernel/workqueue_internal.h @@ -48,7 +48,7 @@ struct worker { /* A: runs through worker->node */ unsigned long last_active; /* K: last active timestamp */ - unsigned int flags; /* X: flags */ + unsigned int flags; /* L: flags */ int id; /* I: worker id */ /* -- GitLab From c0ab017d43f4c4147f7ecf3ca3cb872a416e17c7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:22 -1000 Subject: [PATCH 0876/3445] workqueue: Cleanups around process_scheduled_works() * Drop the trivial optimization in worker_thread() where it bypasses calling process_scheduled_works() if the first work item isn't linked. This is a mostly pointless micro optimization and gets in the way of improving the work processing path. * Consolidate pool->watchdog_ts updates in the two callers into process_scheduled_works(). Signed-off-by: Tejun Heo --- kernel/workqueue.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 598009ad97d1a..20722de9937a0 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -2652,9 +2652,15 @@ __acquires(&pool->lock) */ static void process_scheduled_works(struct worker *worker) { - while (!list_empty(&worker->scheduled)) { - struct work_struct *work = list_first_entry(&worker->scheduled, - struct work_struct, entry); + struct work_struct *work; + bool first = true; + + while ((work = list_first_entry_or_null(&worker->scheduled, + struct work_struct, entry))) { + if (first) { + worker->pool->watchdog_ts = jiffies; + first = false; + } process_one_work(worker, work); } } @@ -2735,17 +2741,8 @@ recheck: list_first_entry(&pool->worklist, struct work_struct, entry); - pool->watchdog_ts = jiffies; - - if (likely(!(*work_data_bits(work) & WORK_STRUCT_LINKED))) { - /* optimization path, not strictly necessary */ - process_one_work(worker, work); - if (unlikely(!list_empty(&worker->scheduled))) - process_scheduled_works(worker); - } else { - move_linked_works(work, &worker->scheduled, NULL); - process_scheduled_works(worker); - } + move_linked_works(work, &worker->scheduled, NULL); + process_scheduled_works(worker); } while (keep_working(pool)); worker_set_flags(worker, WORKER_PREP); @@ -2820,7 +2817,6 @@ repeat: struct pool_workqueue, mayday_node); struct worker_pool *pool = pwq->pool; struct work_struct *work, *n; - bool first = true; __set_current_state(TASK_RUNNING); list_del_init(&pwq->mayday_node); @@ -2838,12 +2834,9 @@ repeat: WARN_ON_ONCE(!list_empty(scheduled)); list_for_each_entry_safe(work, n, &pool->worklist, entry) { if (get_work_pwq(work) == pwq) { - if (first) - pool->watchdog_ts = jiffies; move_linked_works(work, scheduled, &n); pwq->stats[PWQ_STAT_RESCUED]++; } - first = false; } if (!list_empty(scheduled)) { -- GitLab From fe089f87cccb066e8ad20f49ddf05e95adc1fa8d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:22 -1000 Subject: [PATCH 0877/3445] workqueue: Not all work insertion needs to wake up a worker insert_work() always tried to wake up a worker; however, the only time it needs to try to wake up a worker is when a new active work item is queued. When a work item goes on the inactive list or queueing a flush work item, there's no reason to try to wake up a worker. This patch moves the worker wakeup logic out of insert_work() and places it in the active new work item queueing path in __queue_work(). While at it: * __queue_work() is dereferencing pwq->pool repeatedly. Add local variable pool. * Every caller of insert_work() calls debug_work_activate(). Consolidate the invocations into insert_work(). * In __queue_work() pool->watchdog_ts update is relocated slightly. This is to better accommodate future changes. This makes wakeups more precise and will help the planned change to assign work items to workers before waking them up. No behavior changes intended. v2: WARN_ON_ONCE(pool != last_pool) added in __queue_work() to clarify as suggested by Lai. Signed-off-by: Tejun Heo Cc: Lai Jiangshan --- kernel/workqueue.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 20722de9937a0..1332bd545b929 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1542,7 +1542,7 @@ fail: static void insert_work(struct pool_workqueue *pwq, struct work_struct *work, struct list_head *head, unsigned int extra_flags) { - struct worker_pool *pool = pwq->pool; + debug_work_activate(work); /* record the work call stack in order to print it in KASAN reports */ kasan_record_aux_stack_noalloc(work); @@ -1551,9 +1551,6 @@ static void insert_work(struct pool_workqueue *pwq, struct work_struct *work, set_work_pwq(work, pwq, extra_flags); list_add_tail(&work->entry, head); get_pwq(pwq); - - if (__need_more_worker(pool)) - wake_up_worker(pool); } /* @@ -1607,8 +1604,7 @@ static void __queue_work(int cpu, struct workqueue_struct *wq, struct work_struct *work) { struct pool_workqueue *pwq; - struct worker_pool *last_pool; - struct list_head *worklist; + struct worker_pool *last_pool, *pool; unsigned int work_flags; unsigned int req_cpu = cpu; @@ -1642,13 +1638,15 @@ retry: pwq = per_cpu_ptr(wq->cpu_pwqs, cpu); } + pool = pwq->pool; + /* * If @work was previously on a different pool, it might still be * running there, in which case the work needs to be queued on that * pool to guarantee non-reentrancy. */ last_pool = get_work_pool(work); - if (last_pool && last_pool != pwq->pool) { + if (last_pool && last_pool != pool) { struct worker *worker; raw_spin_lock(&last_pool->lock); @@ -1657,13 +1655,15 @@ retry: if (worker && worker->current_pwq->wq == wq) { pwq = worker->current_pwq; + pool = pwq->pool; + WARN_ON_ONCE(pool != last_pool); } else { /* meh... not running there, queue here */ raw_spin_unlock(&last_pool->lock); - raw_spin_lock(&pwq->pool->lock); + raw_spin_lock(&pool->lock); } } else { - raw_spin_lock(&pwq->pool->lock); + raw_spin_lock(&pool->lock); } /* @@ -1676,7 +1676,7 @@ retry: */ if (unlikely(!pwq->refcnt)) { if (wq->flags & WQ_UNBOUND) { - raw_spin_unlock(&pwq->pool->lock); + raw_spin_unlock(&pool->lock); cpu_relax(); goto retry; } @@ -1695,21 +1695,22 @@ retry: work_flags = work_color_to_flags(pwq->work_color); if (likely(pwq->nr_active < pwq->max_active)) { + if (list_empty(&pool->worklist)) + pool->watchdog_ts = jiffies; + trace_workqueue_activate_work(work); pwq->nr_active++; - worklist = &pwq->pool->worklist; - if (list_empty(worklist)) - pwq->pool->watchdog_ts = jiffies; + insert_work(pwq, work, &pool->worklist, work_flags); + + if (__need_more_worker(pool)) + wake_up_worker(pool); } else { work_flags |= WORK_STRUCT_INACTIVE; - worklist = &pwq->inactive_works; + insert_work(pwq, work, &pwq->inactive_works, work_flags); } - debug_work_activate(work); - insert_work(pwq, work, worklist, work_flags); - out: - raw_spin_unlock(&pwq->pool->lock); + raw_spin_unlock(&pool->lock); rcu_read_unlock(); } @@ -3012,7 +3013,6 @@ static void insert_wq_barrier(struct pool_workqueue *pwq, pwq->nr_in_flight[work_color]++; work_flags |= work_color_to_flags(work_color); - debug_work_activate(&barr->work); insert_work(pwq, &barr->work, head, work_flags); } -- GitLab From ee1ceef72754427e5167743108c52f826fa4ca5b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:23 -1000 Subject: [PATCH 0878/3445] workqueue: Rename wq->cpu_pwqs to wq->cpu_pwq wq->cpu_pwqs is a percpu variable carraying one pointer to a pool_workqueue. The field name being plural is unusual and confusing. Rename it to singular. This patch doesn't cause any functional changes. Signed-off-by: Tejun Heo --- kernel/workqueue.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 1332bd545b929..ea94ad63386e9 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -321,7 +321,7 @@ struct workqueue_struct { /* hot fields used during command issue, aligned to cacheline */ unsigned int flags ____cacheline_aligned; /* WQ: WQ_* flags */ - struct pool_workqueue __percpu *cpu_pwqs; /* I: per-cpu pwqs */ + struct pool_workqueue __percpu *cpu_pwq; /* I: per-cpu pwqs */ struct pool_workqueue __rcu *numa_pwq_tbl[]; /* PWR: unbound pwqs indexed by node */ }; @@ -1635,7 +1635,7 @@ retry: } else { if (req_cpu == WORK_CPU_UNBOUND) cpu = raw_smp_processor_id(); - pwq = per_cpu_ptr(wq->cpu_pwqs, cpu); + pwq = per_cpu_ptr(wq->cpu_pwq, cpu); } pool = pwq->pool; @@ -3826,7 +3826,7 @@ static void rcu_free_wq(struct rcu_head *rcu) wq_free_lockdep(wq); if (!(wq->flags & WQ_UNBOUND)) - free_percpu(wq->cpu_pwqs); + free_percpu(wq->cpu_pwq); else free_workqueue_attrs(wq->unbound_attrs); @@ -4518,13 +4518,13 @@ static int alloc_and_link_pwqs(struct workqueue_struct *wq) int cpu, ret; if (!(wq->flags & WQ_UNBOUND)) { - wq->cpu_pwqs = alloc_percpu(struct pool_workqueue); - if (!wq->cpu_pwqs) + wq->cpu_pwq = alloc_percpu(struct pool_workqueue); + if (!wq->cpu_pwq) return -ENOMEM; for_each_possible_cpu(cpu) { struct pool_workqueue *pwq = - per_cpu_ptr(wq->cpu_pwqs, cpu); + per_cpu_ptr(wq->cpu_pwq, cpu); struct worker_pool *cpu_pools = per_cpu(cpu_worker_pools, cpu); @@ -4905,7 +4905,7 @@ bool workqueue_congested(int cpu, struct workqueue_struct *wq) cpu = smp_processor_id(); if (!(wq->flags & WQ_UNBOUND)) - pwq = per_cpu_ptr(wq->cpu_pwqs, cpu); + pwq = per_cpu_ptr(wq->cpu_pwq, cpu); else pwq = unbound_pwq_by_node(wq, cpu_to_node(cpu)); -- GitLab From 797e8345cbb0d2913300ee9838eb74cce19485cf Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:23 -1000 Subject: [PATCH 0879/3445] workqueue: Relocate worker and work management functions Collect first_idle_worker(), worker_enter/leave_idle(), find_worker_executing_work(), move_linked_works() and wake_up_worker() into one place. These functions will later be used to implement higher level worker management logic. No functional changes. Signed-off-by: Tejun Heo --- kernel/workqueue.c | 340 ++++++++++++++++++++++----------------------- 1 file changed, 168 insertions(+), 172 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index ea94ad63386e9..8f5338e7331c1 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -869,36 +869,6 @@ static bool too_many_workers(struct worker_pool *pool) return nr_idle > 2 && (nr_idle - 2) * MAX_IDLE_WORKERS_RATIO >= nr_busy; } -/* - * Wake up functions. - */ - -/* Return the first idle worker. Called with pool->lock held. */ -static struct worker *first_idle_worker(struct worker_pool *pool) -{ - if (unlikely(list_empty(&pool->idle_list))) - return NULL; - - return list_first_entry(&pool->idle_list, struct worker, entry); -} - -/** - * wake_up_worker - wake up an idle worker - * @pool: worker pool to wake worker from - * - * Wake up the first idle worker of @pool. - * - * CONTEXT: - * raw_spin_lock_irq(pool->lock). - */ -static void wake_up_worker(struct worker_pool *pool) -{ - struct worker *worker = first_idle_worker(pool); - - if (likely(worker)) - wake_up_process(worker->task); -} - /** * worker_set_flags - set worker flags and adjust nr_running accordingly * @worker: self @@ -947,6 +917,174 @@ static inline void worker_clr_flags(struct worker *worker, unsigned int flags) pool->nr_running++; } +/* Return the first idle worker. Called with pool->lock held. */ +static struct worker *first_idle_worker(struct worker_pool *pool) +{ + if (unlikely(list_empty(&pool->idle_list))) + return NULL; + + return list_first_entry(&pool->idle_list, struct worker, entry); +} + +/** + * worker_enter_idle - enter idle state + * @worker: worker which is entering idle state + * + * @worker is entering idle state. Update stats and idle timer if + * necessary. + * + * LOCKING: + * raw_spin_lock_irq(pool->lock). + */ +static void worker_enter_idle(struct worker *worker) +{ + struct worker_pool *pool = worker->pool; + + if (WARN_ON_ONCE(worker->flags & WORKER_IDLE) || + WARN_ON_ONCE(!list_empty(&worker->entry) && + (worker->hentry.next || worker->hentry.pprev))) + return; + + /* can't use worker_set_flags(), also called from create_worker() */ + worker->flags |= WORKER_IDLE; + pool->nr_idle++; + worker->last_active = jiffies; + + /* idle_list is LIFO */ + list_add(&worker->entry, &pool->idle_list); + + if (too_many_workers(pool) && !timer_pending(&pool->idle_timer)) + mod_timer(&pool->idle_timer, jiffies + IDLE_WORKER_TIMEOUT); + + /* Sanity check nr_running. */ + WARN_ON_ONCE(pool->nr_workers == pool->nr_idle && pool->nr_running); +} + +/** + * worker_leave_idle - leave idle state + * @worker: worker which is leaving idle state + * + * @worker is leaving idle state. Update stats. + * + * LOCKING: + * raw_spin_lock_irq(pool->lock). + */ +static void worker_leave_idle(struct worker *worker) +{ + struct worker_pool *pool = worker->pool; + + if (WARN_ON_ONCE(!(worker->flags & WORKER_IDLE))) + return; + worker_clr_flags(worker, WORKER_IDLE); + pool->nr_idle--; + list_del_init(&worker->entry); +} + +/** + * find_worker_executing_work - find worker which is executing a work + * @pool: pool of interest + * @work: work to find worker for + * + * Find a worker which is executing @work on @pool by searching + * @pool->busy_hash which is keyed by the address of @work. For a worker + * to match, its current execution should match the address of @work and + * its work function. This is to avoid unwanted dependency between + * unrelated work executions through a work item being recycled while still + * being executed. + * + * This is a bit tricky. A work item may be freed once its execution + * starts and nothing prevents the freed area from being recycled for + * another work item. If the same work item address ends up being reused + * before the original execution finishes, workqueue will identify the + * recycled work item as currently executing and make it wait until the + * current execution finishes, introducing an unwanted dependency. + * + * This function checks the work item address and work function to avoid + * false positives. Note that this isn't complete as one may construct a + * work function which can introduce dependency onto itself through a + * recycled work item. Well, if somebody wants to shoot oneself in the + * foot that badly, there's only so much we can do, and if such deadlock + * actually occurs, it should be easy to locate the culprit work function. + * + * CONTEXT: + * raw_spin_lock_irq(pool->lock). + * + * Return: + * Pointer to worker which is executing @work if found, %NULL + * otherwise. + */ +static struct worker *find_worker_executing_work(struct worker_pool *pool, + struct work_struct *work) +{ + struct worker *worker; + + hash_for_each_possible(pool->busy_hash, worker, hentry, + (unsigned long)work) + if (worker->current_work == work && + worker->current_func == work->func) + return worker; + + return NULL; +} + +/** + * move_linked_works - move linked works to a list + * @work: start of series of works to be scheduled + * @head: target list to append @work to + * @nextp: out parameter for nested worklist walking + * + * Schedule linked works starting from @work to @head. Work series to + * be scheduled starts at @work and includes any consecutive work with + * WORK_STRUCT_LINKED set in its predecessor. + * + * If @nextp is not NULL, it's updated to point to the next work of + * the last scheduled work. This allows move_linked_works() to be + * nested inside outer list_for_each_entry_safe(). + * + * CONTEXT: + * raw_spin_lock_irq(pool->lock). + */ +static void move_linked_works(struct work_struct *work, struct list_head *head, + struct work_struct **nextp) +{ + struct work_struct *n; + + /* + * Linked worklist will always end before the end of the list, + * use NULL for list head. + */ + list_for_each_entry_safe_from(work, n, NULL, entry) { + list_move_tail(&work->entry, head); + if (!(*work_data_bits(work) & WORK_STRUCT_LINKED)) + break; + } + + /* + * If we're already inside safe list traversal and have moved + * multiple works to the scheduled queue, the next position + * needs to be updated. + */ + if (nextp) + *nextp = n; +} + +/** + * wake_up_worker - wake up an idle worker + * @pool: worker pool to wake worker from + * + * Wake up the first idle worker of @pool. + * + * CONTEXT: + * raw_spin_lock_irq(pool->lock). + */ +static void wake_up_worker(struct worker_pool *pool) +{ + struct worker *worker = first_idle_worker(pool); + + if (likely(worker)) + wake_up_process(worker->task); +} + #ifdef CONFIG_WQ_CPU_INTENSIVE_REPORT /* @@ -1202,94 +1340,6 @@ work_func_t wq_worker_last_func(struct task_struct *task) return worker->last_func; } -/** - * find_worker_executing_work - find worker which is executing a work - * @pool: pool of interest - * @work: work to find worker for - * - * Find a worker which is executing @work on @pool by searching - * @pool->busy_hash which is keyed by the address of @work. For a worker - * to match, its current execution should match the address of @work and - * its work function. This is to avoid unwanted dependency between - * unrelated work executions through a work item being recycled while still - * being executed. - * - * This is a bit tricky. A work item may be freed once its execution - * starts and nothing prevents the freed area from being recycled for - * another work item. If the same work item address ends up being reused - * before the original execution finishes, workqueue will identify the - * recycled work item as currently executing and make it wait until the - * current execution finishes, introducing an unwanted dependency. - * - * This function checks the work item address and work function to avoid - * false positives. Note that this isn't complete as one may construct a - * work function which can introduce dependency onto itself through a - * recycled work item. Well, if somebody wants to shoot oneself in the - * foot that badly, there's only so much we can do, and if such deadlock - * actually occurs, it should be easy to locate the culprit work function. - * - * CONTEXT: - * raw_spin_lock_irq(pool->lock). - * - * Return: - * Pointer to worker which is executing @work if found, %NULL - * otherwise. - */ -static struct worker *find_worker_executing_work(struct worker_pool *pool, - struct work_struct *work) -{ - struct worker *worker; - - hash_for_each_possible(pool->busy_hash, worker, hentry, - (unsigned long)work) - if (worker->current_work == work && - worker->current_func == work->func) - return worker; - - return NULL; -} - -/** - * move_linked_works - move linked works to a list - * @work: start of series of works to be scheduled - * @head: target list to append @work to - * @nextp: out parameter for nested worklist walking - * - * Schedule linked works starting from @work to @head. Work series to - * be scheduled starts at @work and includes any consecutive work with - * WORK_STRUCT_LINKED set in its predecessor. - * - * If @nextp is not NULL, it's updated to point to the next work of - * the last scheduled work. This allows move_linked_works() to be - * nested inside outer list_for_each_entry_safe(). - * - * CONTEXT: - * raw_spin_lock_irq(pool->lock). - */ -static void move_linked_works(struct work_struct *work, struct list_head *head, - struct work_struct **nextp) -{ - struct work_struct *n; - - /* - * Linked worklist will always end before the end of the list, - * use NULL for list head. - */ - list_for_each_entry_safe_from(work, n, NULL, entry) { - list_move_tail(&work->entry, head); - if (!(*work_data_bits(work) & WORK_STRUCT_LINKED)) - break; - } - - /* - * If we're already inside safe list traversal and have moved - * multiple works to the scheduled queue, the next position - * needs to be updated. - */ - if (nextp) - *nextp = n; -} - /** * get_pwq - get an extra reference on the specified pool_workqueue * @pwq: pool_workqueue to get @@ -1974,60 +2024,6 @@ bool queue_rcu_work(struct workqueue_struct *wq, struct rcu_work *rwork) } EXPORT_SYMBOL(queue_rcu_work); -/** - * worker_enter_idle - enter idle state - * @worker: worker which is entering idle state - * - * @worker is entering idle state. Update stats and idle timer if - * necessary. - * - * LOCKING: - * raw_spin_lock_irq(pool->lock). - */ -static void worker_enter_idle(struct worker *worker) -{ - struct worker_pool *pool = worker->pool; - - if (WARN_ON_ONCE(worker->flags & WORKER_IDLE) || - WARN_ON_ONCE(!list_empty(&worker->entry) && - (worker->hentry.next || worker->hentry.pprev))) - return; - - /* can't use worker_set_flags(), also called from create_worker() */ - worker->flags |= WORKER_IDLE; - pool->nr_idle++; - worker->last_active = jiffies; - - /* idle_list is LIFO */ - list_add(&worker->entry, &pool->idle_list); - - if (too_many_workers(pool) && !timer_pending(&pool->idle_timer)) - mod_timer(&pool->idle_timer, jiffies + IDLE_WORKER_TIMEOUT); - - /* Sanity check nr_running. */ - WARN_ON_ONCE(pool->nr_workers == pool->nr_idle && pool->nr_running); -} - -/** - * worker_leave_idle - leave idle state - * @worker: worker which is leaving idle state - * - * @worker is leaving idle state. Update stats. - * - * LOCKING: - * raw_spin_lock_irq(pool->lock). - */ -static void worker_leave_idle(struct worker *worker) -{ - struct worker_pool *pool = worker->pool; - - if (WARN_ON_ONCE(!(worker->flags & WORKER_IDLE))) - return; - worker_clr_flags(worker, WORKER_IDLE); - pool->nr_idle--; - list_del_init(&worker->entry); -} - static struct worker *alloc_worker(int node) { struct worker *worker; -- GitLab From fcecfa8f271acdf130acbb30842e7848a138af0f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:23 -1000 Subject: [PATCH 0880/3445] workqueue: Remove module param disable_numa and sysfs knobs pool_ids and numa Unbound workqueue CPU affinity is going to receive an overhaul and the NUMA specific knobs won't make sense anymore. Remove them. Also, the pool_ids knob was used for debugging and not really meaningful given that there is no visibility into the pools associated with those IDs. Remove it too. A future patch will improve overall visibility. Signed-off-by: Tejun Heo --- .../admin-guide/kernel-parameters.txt | 9 --- kernel/workqueue.c | 73 ------------------- 2 files changed, 82 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index d1edee0fd5ec3..2b89cbc39713a 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -6992,15 +6992,6 @@ threshold repeatedly. They are likely good candidates for using WQ_UNBOUND workqueues instead. - workqueue.disable_numa - By default, all work items queued to unbound - workqueues are affine to the NUMA nodes they're - issued on, which results in better behavior in - general. If NUMA affinity needs to be disabled for - whatever reason, this option can be used. Note - that this also can be controlled per-workqueue for - workqueues visible under /sys/bus/workqueue/. - workqueue.power_efficient Per-cpu workqueues are generally preferred because they show better performance thanks to cache diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 8f5338e7331c1..4347f493eca12 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -340,9 +340,6 @@ static cpumask_var_t *wq_numa_possible_cpumask; static unsigned long wq_cpu_intensive_thresh_us = ULONG_MAX; module_param_named(cpu_intensive_thresh_us, wq_cpu_intensive_thresh_us, ulong, 0644); -static bool wq_disable_numa; -module_param_named(disable_numa, wq_disable_numa, bool, 0444); - /* see the comment above the definition of WQ_POWER_EFFICIENT */ static bool wq_power_efficient = IS_ENABLED(CONFIG_WQ_POWER_EFFICIENT_DEFAULT); module_param_named(power_efficient, wq_power_efficient, bool, 0444); @@ -5794,10 +5791,8 @@ out_unlock: * * Unbound workqueues have the following extra attributes. * - * pool_ids RO int : the associated pool IDs for each node * nice RW int : nice value of the workers * cpumask RW mask : bitmask of allowed CPUs for the workers - * numa RW bool : whether enable NUMA affinity */ struct wq_device { struct workqueue_struct *wq; @@ -5850,28 +5845,6 @@ static struct attribute *wq_sysfs_attrs[] = { }; ATTRIBUTE_GROUPS(wq_sysfs); -static ssize_t wq_pool_ids_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct workqueue_struct *wq = dev_to_wq(dev); - const char *delim = ""; - int node, written = 0; - - cpus_read_lock(); - rcu_read_lock(); - for_each_node(node) { - written += scnprintf(buf + written, PAGE_SIZE - written, - "%s%d:%d", delim, node, - unbound_pwq_by_node(wq, node)->pool->id); - delim = " "; - } - written += scnprintf(buf + written, PAGE_SIZE - written, "\n"); - rcu_read_unlock(); - cpus_read_unlock(); - - return written; -} - static ssize_t wq_nice_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -5962,50 +5935,9 @@ out_unlock: return ret ?: count; } -static ssize_t wq_numa_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct workqueue_struct *wq = dev_to_wq(dev); - int written; - - mutex_lock(&wq->mutex); - written = scnprintf(buf, PAGE_SIZE, "%d\n", - !wq->unbound_attrs->no_numa); - mutex_unlock(&wq->mutex); - - return written; -} - -static ssize_t wq_numa_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct workqueue_struct *wq = dev_to_wq(dev); - struct workqueue_attrs *attrs; - int v, ret = -ENOMEM; - - apply_wqattrs_lock(); - - attrs = wq_sysfs_prep_attrs(wq); - if (!attrs) - goto out_unlock; - - ret = -EINVAL; - if (sscanf(buf, "%d", &v) == 1) { - attrs->no_numa = !v; - ret = apply_workqueue_attrs_locked(wq, attrs); - } - -out_unlock: - apply_wqattrs_unlock(); - free_workqueue_attrs(attrs); - return ret ?: count; -} - static struct device_attribute wq_sysfs_unbound_attrs[] = { - __ATTR(pool_ids, 0444, wq_pool_ids_show, NULL), __ATTR(nice, 0644, wq_nice_show, wq_nice_store), __ATTR(cpumask, 0644, wq_cpumask_show, wq_cpumask_store), - __ATTR(numa, 0644, wq_numa_show, wq_numa_store), __ATTR_NULL, }; @@ -6379,11 +6311,6 @@ static void __init wq_numa_init(void) if (num_possible_nodes() <= 1) return; - if (wq_disable_numa) { - pr_info("workqueue: NUMA affinity support disabled\n"); - return; - } - for_each_possible_cpu(cpu) { if (WARN_ON(cpu_to_node(cpu) == NUMA_NO_NODE)) { pr_warn("workqueue: NUMA node mapping not available for cpu%d, disabling NUMA support\n", cpu); -- GitLab From 967b494e2fd143a9c1a3201422aceadb5fa9fbfc Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:23 -1000 Subject: [PATCH 0881/3445] workqueue: Use a kthread_worker to release pool_workqueues pool_workqueue release path is currently bounced to system_wq; however, this is a bit tricky because this bouncing occurs while holding a pool lock and thus has risk of causing a A-A deadlock. This is currently addressed by the fact that only unbound workqueues use this bouncing path and system_wq is a per-cpu workqueue. While this works, it's brittle and requires a work-around like setting the lockdep subclass for the lock of unbound pools. Besides, future changes will use the bouncing path for per-cpu workqueues too making the current approach unusable. Let's just use a dedicated kthread_worker to untangle the dependency. This is just one more kthread for all workqueues and makes the pwq release logic simpler and more robust. Signed-off-by: Tejun Heo --- kernel/workqueue.c | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 4347f493eca12..01bf22c5d515e 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -257,12 +257,12 @@ struct pool_workqueue { u64 stats[PWQ_NR_STATS]; /* - * Release of unbound pwq is punted to system_wq. See put_pwq() - * and pwq_unbound_release_workfn() for details. pool_workqueue - * itself is also RCU protected so that the first pwq can be - * determined without grabbing wq->mutex. + * Release of unbound pwq is punted to a kthread_worker. See put_pwq() + * and pwq_unbound_release_workfn() for details. pool_workqueue itself + * is also RCU protected so that the first pwq can be determined without + * grabbing wq->mutex. */ - struct work_struct unbound_release_work; + struct kthread_work unbound_release_work; struct rcu_head rcu; } __aligned(1 << WORK_STRUCT_FLAG_BITS); @@ -395,6 +395,13 @@ static struct workqueue_attrs *unbound_std_wq_attrs[NR_STD_WORKER_POOLS]; /* I: attributes used when instantiating ordered pools on demand */ static struct workqueue_attrs *ordered_wq_attrs[NR_STD_WORKER_POOLS]; +/* + * I: kthread_worker to release pwq's. pwq release needs to be bounced to a + * process context while holding a pool lock. Bounce to a dedicated kthread + * worker to avoid A-A deadlocks. + */ +static struct kthread_worker *pwq_release_worker; + struct workqueue_struct *system_wq __read_mostly; EXPORT_SYMBOL(system_wq); struct workqueue_struct *system_highpri_wq __read_mostly; @@ -1366,14 +1373,10 @@ static void put_pwq(struct pool_workqueue *pwq) if (WARN_ON_ONCE(!(pwq->wq->flags & WQ_UNBOUND))) return; /* - * @pwq can't be released under pool->lock, bounce to - * pwq_unbound_release_workfn(). This never recurses on the same - * pool->lock as this path is taken only for unbound workqueues and - * the release work item is scheduled on a per-cpu workqueue. To - * avoid lockdep warning, unbound pool->locks are given lockdep - * subclass of 1 in get_unbound_pool(). + * @pwq can't be released under pool->lock, bounce to a dedicated + * kthread_worker to avoid A-A deadlocks. */ - schedule_work(&pwq->unbound_release_work); + kthread_queue_work(pwq_release_worker, &pwq->unbound_release_work); } /** @@ -3965,7 +3968,6 @@ static struct worker_pool *get_unbound_pool(const struct workqueue_attrs *attrs) if (!pool || init_worker_pool(pool) < 0) goto fail; - lockdep_set_subclass(&pool->lock, 1); /* see put_pwq() */ copy_workqueue_attrs(pool->attrs, attrs); pool->node = target_node; @@ -3999,10 +4001,10 @@ static void rcu_free_pwq(struct rcu_head *rcu) } /* - * Scheduled on system_wq by put_pwq() when an unbound pwq hits zero refcnt - * and needs to be destroyed. + * Scheduled on pwq_release_worker by put_pwq() when an unbound pwq hits zero + * refcnt and needs to be destroyed. */ -static void pwq_unbound_release_workfn(struct work_struct *work) +static void pwq_unbound_release_workfn(struct kthread_work *work) { struct pool_workqueue *pwq = container_of(work, struct pool_workqueue, unbound_release_work); @@ -4110,7 +4112,8 @@ static void init_pwq(struct pool_workqueue *pwq, struct workqueue_struct *wq, INIT_LIST_HEAD(&pwq->inactive_works); INIT_LIST_HEAD(&pwq->pwqs_node); INIT_LIST_HEAD(&pwq->mayday_node); - INIT_WORK(&pwq->unbound_release_work, pwq_unbound_release_workfn); + kthread_init_work(&pwq->unbound_release_work, + pwq_unbound_release_workfn); } /* sync @pwq with the current state of its associated wq and link it */ @@ -6433,6 +6436,9 @@ static void __init wq_cpu_intensive_thresh_init(void) if (wq_cpu_intensive_thresh_us != ULONG_MAX) return; + pwq_release_worker = kthread_create_worker(0, "pool_workqueue_release"); + BUG_ON(IS_ERR(pwq_release_worker)); + /* * The default of 10ms is derived from the fact that most modern (as of * 2023) processors can do a lot in 10ms and that it's just below what -- GitLab From 687a9aa56f811b381e63f7f8f9149428ac708a3b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:23 -1000 Subject: [PATCH 0882/3445] workqueue: Make per-cpu pool_workqueues allocated and released like unbound ones Currently, all per-cpu pwq's (pool_workqueue's) are allocated directly through a per-cpu allocation and thus, unlike unbound workqueues, not reference counted. This difference in lifetime management between the two types is a bit confusing. Unbound workqueues are currently accessed through wq->numa_pwq_tbl[] which isn't suitiable for the planned CPU locality related improvements. The plan is to unify pwq handling across per-cpu and unbound workqueues so that they're always accessed through wq->cpu_pwq. In preparation, this patch makes per-cpu pwq's to be allocated, reference counted and released the same way as unbound pwq's. wq->cpu_pwq now holds pointers to pwq's instead of containing them directly. pwq_unbound_release_workfn() is renamed to pwq_release_workfn() as it's now also used for per-cpu work items. Signed-off-by: Tejun Heo --- kernel/workqueue.c | 74 +++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 01bf22c5d515e..05bf5427124a9 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -258,11 +258,11 @@ struct pool_workqueue { /* * Release of unbound pwq is punted to a kthread_worker. See put_pwq() - * and pwq_unbound_release_workfn() for details. pool_workqueue itself - * is also RCU protected so that the first pwq can be determined without + * and pwq_release_workfn() for details. pool_workqueue itself is also + * RCU protected so that the first pwq can be determined without * grabbing wq->mutex. */ - struct kthread_work unbound_release_work; + struct kthread_work release_work; struct rcu_head rcu; } __aligned(1 << WORK_STRUCT_FLAG_BITS); @@ -321,7 +321,7 @@ struct workqueue_struct { /* hot fields used during command issue, aligned to cacheline */ unsigned int flags ____cacheline_aligned; /* WQ: WQ_* flags */ - struct pool_workqueue __percpu *cpu_pwq; /* I: per-cpu pwqs */ + struct pool_workqueue __percpu **cpu_pwq; /* I: per-cpu pwqs */ struct pool_workqueue __rcu *numa_pwq_tbl[]; /* PWR: unbound pwqs indexed by node */ }; @@ -1370,13 +1370,11 @@ static void put_pwq(struct pool_workqueue *pwq) lockdep_assert_held(&pwq->pool->lock); if (likely(--pwq->refcnt)) return; - if (WARN_ON_ONCE(!(pwq->wq->flags & WQ_UNBOUND))) - return; /* * @pwq can't be released under pool->lock, bounce to a dedicated * kthread_worker to avoid A-A deadlocks. */ - kthread_queue_work(pwq_release_worker, &pwq->unbound_release_work); + kthread_queue_work(pwq_release_worker, &pwq->release_work); } /** @@ -1685,7 +1683,7 @@ retry: } else { if (req_cpu == WORK_CPU_UNBOUND) cpu = raw_smp_processor_id(); - pwq = per_cpu_ptr(wq->cpu_pwq, cpu); + pwq = *per_cpu_ptr(wq->cpu_pwq, cpu); } pool = pwq->pool; @@ -4004,31 +4002,30 @@ static void rcu_free_pwq(struct rcu_head *rcu) * Scheduled on pwq_release_worker by put_pwq() when an unbound pwq hits zero * refcnt and needs to be destroyed. */ -static void pwq_unbound_release_workfn(struct kthread_work *work) +static void pwq_release_workfn(struct kthread_work *work) { struct pool_workqueue *pwq = container_of(work, struct pool_workqueue, - unbound_release_work); + release_work); struct workqueue_struct *wq = pwq->wq; struct worker_pool *pool = pwq->pool; bool is_last = false; /* - * when @pwq is not linked, it doesn't hold any reference to the + * When @pwq is not linked, it doesn't hold any reference to the * @wq, and @wq is invalid to access. */ if (!list_empty(&pwq->pwqs_node)) { - if (WARN_ON_ONCE(!(wq->flags & WQ_UNBOUND))) - return; - mutex_lock(&wq->mutex); list_del_rcu(&pwq->pwqs_node); is_last = list_empty(&wq->pwqs); mutex_unlock(&wq->mutex); } - mutex_lock(&wq_pool_mutex); - put_unbound_pool(pool); - mutex_unlock(&wq_pool_mutex); + if (wq->flags & WQ_UNBOUND) { + mutex_lock(&wq_pool_mutex); + put_unbound_pool(pool); + mutex_unlock(&wq_pool_mutex); + } call_rcu(&pwq->rcu, rcu_free_pwq); @@ -4112,8 +4109,7 @@ static void init_pwq(struct pool_workqueue *pwq, struct workqueue_struct *wq, INIT_LIST_HEAD(&pwq->inactive_works); INIT_LIST_HEAD(&pwq->pwqs_node); INIT_LIST_HEAD(&pwq->mayday_node); - kthread_init_work(&pwq->unbound_release_work, - pwq_unbound_release_workfn); + kthread_init_work(&pwq->release_work, pwq_release_workfn); } /* sync @pwq with the current state of its associated wq and link it */ @@ -4514,20 +4510,25 @@ static int alloc_and_link_pwqs(struct workqueue_struct *wq) int cpu, ret; if (!(wq->flags & WQ_UNBOUND)) { - wq->cpu_pwq = alloc_percpu(struct pool_workqueue); + wq->cpu_pwq = alloc_percpu(struct pool_workqueue *); if (!wq->cpu_pwq) - return -ENOMEM; + goto enomem; for_each_possible_cpu(cpu) { - struct pool_workqueue *pwq = + struct pool_workqueue **pwq_p = per_cpu_ptr(wq->cpu_pwq, cpu); - struct worker_pool *cpu_pools = - per_cpu(cpu_worker_pools, cpu); + struct worker_pool *pool = + &(per_cpu_ptr(cpu_worker_pools, cpu)[highpri]); - init_pwq(pwq, wq, &cpu_pools[highpri]); + *pwq_p = kmem_cache_alloc_node(pwq_cache, GFP_KERNEL, + pool->node); + if (!*pwq_p) + goto enomem; + + init_pwq(*pwq_p, wq, pool); mutex_lock(&wq->mutex); - link_pwq(pwq); + link_pwq(*pwq_p); mutex_unlock(&wq->mutex); } return 0; @@ -4546,6 +4547,15 @@ static int alloc_and_link_pwqs(struct workqueue_struct *wq) cpus_read_unlock(); return ret; + +enomem: + if (wq->cpu_pwq) { + for_each_possible_cpu(cpu) + kfree(*per_cpu_ptr(wq->cpu_pwq, cpu)); + free_percpu(wq->cpu_pwq); + wq->cpu_pwq = NULL; + } + return -ENOMEM; } static int wq_clamp_max_active(int max_active, unsigned int flags, @@ -4719,7 +4729,7 @@ static bool pwq_busy(struct pool_workqueue *pwq) void destroy_workqueue(struct workqueue_struct *wq) { struct pool_workqueue *pwq; - int node; + int cpu, node; /* * Remove it from sysfs first so that sanity check failure doesn't @@ -4779,12 +4789,8 @@ void destroy_workqueue(struct workqueue_struct *wq) mutex_unlock(&wq_pool_mutex); if (!(wq->flags & WQ_UNBOUND)) { - wq_unregister_lockdep(wq); - /* - * The base ref is never dropped on per-cpu pwqs. Directly - * schedule RCU free. - */ - call_rcu(&wq->rcu, rcu_free_wq); + for_each_possible_cpu(cpu) + put_pwq_unlocked(*per_cpu_ptr(wq->cpu_pwq, cpu)); } else { /* * We're the sole accessor of @wq at this point. Directly @@ -4901,7 +4907,7 @@ bool workqueue_congested(int cpu, struct workqueue_struct *wq) cpu = smp_processor_id(); if (!(wq->flags & WQ_UNBOUND)) - pwq = per_cpu_ptr(wq->cpu_pwq, cpu); + pwq = *per_cpu_ptr(wq->cpu_pwq, cpu); else pwq = unbound_pwq_by_node(wq, cpu_to_node(cpu)); -- GitLab From 4cbfd3de737b9d00544ff0f673cb75fc37bffb6a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:23 -1000 Subject: [PATCH 0883/3445] workqueue: Call wq_update_unbound_numa() on all CPUs in NUMA node on CPU hotplug When a CPU went online or offline, wq_update_unbound_numa() was called only on the CPU which was going up or down. This works fine because all CPUs on the same NUMA node share the same pool_workqueue slot - one CPU updating it updates it for everyone in the node. However, future changes will make each CPU use a separate pool_workqueue even when they're sharing the same worker_pool, which requires updating pool_workqueue's for all CPUs which may be sharing the same pool_workqueue on hotplug. To accommodate the planned changes, this patch updates workqueue_on/offline_cpu() so that they call wq_update_unbound_numa() for all CPUs sharing the same NUMA node as the CPU going up or down. In the current code, the second+ calls would be noops and there shouldn't be any behavior changes. * As wq_update_unbound_numa() is now called on multiple CPUs per each hotplug event, @cpu is renamed to @hotplug_cpu and another @cpu argument is added. The former indicates the CPU being hot[un]plugged and the latter the CPU whose pool_workqueue is being updated. * In wq_update_unbound_numa(), cpu_off is renamed to off_cpu for consistency with the new @hotplug_cpu. Signed-off-by: Tejun Heo --- kernel/workqueue.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 05bf5427124a9..9f4341885f60c 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -4422,7 +4422,8 @@ int apply_workqueue_attrs(struct workqueue_struct *wq, /** * wq_update_unbound_numa - update NUMA affinity of a wq for CPU hot[un]plug * @wq: the target workqueue - * @cpu: the CPU coming up or going down + * @cpu: the CPU to update pool association for + * @hotplug_cpu: the CPU coming up or going down * @online: whether @cpu is coming up or going down * * This function is to be called from %CPU_DOWN_PREPARE, %CPU_ONLINE and @@ -4442,10 +4443,10 @@ int apply_workqueue_attrs(struct workqueue_struct *wq, * CPU_DOWN_PREPARE. */ static void wq_update_unbound_numa(struct workqueue_struct *wq, int cpu, - bool online) + int hotplug_cpu, bool online) { int node = cpu_to_node(cpu); - int cpu_off = online ? -1 : cpu; + int off_cpu = online ? -1 : hotplug_cpu; struct pool_workqueue *old_pwq = NULL, *pwq; struct workqueue_attrs *target_attrs; cpumask_t *cpumask; @@ -4473,7 +4474,7 @@ static void wq_update_unbound_numa(struct workqueue_struct *wq, int cpu, * and create a new one if they don't match. If the target cpumask * equals the default pwq's, the default pwq should be used. */ - if (wq_calc_node_cpumask(wq->dfl_pwq->pool->attrs, node, cpu_off, cpumask)) { + if (wq_calc_node_cpumask(wq->dfl_pwq->pool->attrs, node, off_cpu, cpumask)) { if (cpumask_equal(cpumask, pwq->pool->attrs->cpumask)) return; } else { @@ -5514,8 +5515,15 @@ int workqueue_online_cpu(unsigned int cpu) } /* update NUMA affinity of unbound workqueues */ - list_for_each_entry(wq, &workqueues, list) - wq_update_unbound_numa(wq, cpu, true); + list_for_each_entry(wq, &workqueues, list) { + int tcpu; + + for_each_possible_cpu(tcpu) { + if (cpu_to_node(tcpu) == cpu_to_node(cpu)) { + wq_update_unbound_numa(wq, tcpu, cpu, true); + } + } + } mutex_unlock(&wq_pool_mutex); return 0; @@ -5533,8 +5541,15 @@ int workqueue_offline_cpu(unsigned int cpu) /* update NUMA affinity of unbound workqueues */ mutex_lock(&wq_pool_mutex); - list_for_each_entry(wq, &workqueues, list) - wq_update_unbound_numa(wq, cpu, false); + list_for_each_entry(wq, &workqueues, list) { + int tcpu; + + for_each_possible_cpu(tcpu) { + if (cpu_to_node(tcpu) == cpu_to_node(cpu)) { + wq_update_unbound_numa(wq, tcpu, cpu, false); + } + } + } mutex_unlock(&wq_pool_mutex); return 0; @@ -6509,7 +6524,8 @@ void __init workqueue_init(void) } list_for_each_entry(wq, &workqueues, list) { - wq_update_unbound_numa(wq, smp_processor_id(), true); + wq_update_unbound_numa(wq, smp_processor_id(), smp_processor_id(), + true); WARN(init_rescuer(wq), "workqueue: failed to create early rescuer for %s", wq->name); -- GitLab From 636b927eba5bc633753f8eb80f35e1d5be806e51 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:23 -1000 Subject: [PATCH 0884/3445] workqueue: Make unbound workqueues to use per-cpu pool_workqueues A pwq (pool_workqueue) represents an association between a workqueue and a worker_pool. When a work item is queued, the workqueue selects the pwq to use, which in turn determines the pool, and queues the work item to the pool through the pwq. pwq is also what implements the maximum concurrency limit - @max_active. As a per-cpu workqueue should be assocaited with a different worker_pool on each CPU, it always had per-cpu pwq's that are accessed through wq->cpu_pwq. However, unbound workqueues were sharing a pwq within each NUMA node by default. The sharing has several downsides: * Because @max_active is per-pwq, the meaning of @max_active changes depending on the machine configuration and whether workqueue NUMA locality support is enabled. * Makes per-cpu and unbound code deviate. * Gets in the way of making workqueue CPU locality awareness more flexible. This patch makes unbound workqueues use per-cpu pwq's the same way per-cpu workqueues do by making the following changes: * wq->numa_pwq_tbl[] is removed and unbound workqueues now use wq->cpu_pwq just like per-cpu workqueues. wq->cpu_pwq is now RCU protected for unbound workqueues. * numa_pwq_tbl_install() is renamed to install_unbound_pwq() and installs the specified pwq to the target CPU's wq->cpu_pwq. * apply_wqattrs_prepare() now always allocates a separate pwq for each CPU unless the workqueue is ordered. If ordered, all CPUs use wq->dfl_pwq. This makes the return value of wq_calc_node_cpumask() unnecessary. It now returns void. * @max_active now means the same thing for both per-cpu and unbound workqueues. WQ_UNBOUND_MAX_ACTIVE now equals WQ_MAX_ACTIVE and documentation is updated accordingly. WQ_UNBOUND_MAX_ACTIVE is no longer used in workqueue implementation and will be removed later. * All unbound pwq operations which used to be per-numa-node are now per-cpu. For most unbound workqueue users, this shouldn't cause noticeable changes. Work item issue and completion will be a small bit faster, flush_workqueue() would become a bit more expensive, and the total concurrency limit would likely become higher. All @max_active==1 use cases are currently being audited for conversion into alloc_ordered_workqueue() and they shouldn't be affected once the audit and conversion is complete. One area where the behavior change may be more noticeable is workqueue_congested() as the reported congestion state is now per CPU instead of NUMA node. There are only two users of this interface - drivers/infiniband/hw/hfi1 and net/smc. Maintainers of both subsystems are cc'd. Inputs on the behavior change would be very much appreciated. Signed-off-by: Tejun Heo Acked-by: Dennis Dalessandro Cc: Jason Gunthorpe Cc: Leon Romanovsky Cc: Karsten Graul Cc: Wenjia Zhang Cc: Jan Karcher --- Documentation/core-api/workqueue.rst | 21 ++- include/linux/workqueue.h | 8 +- kernel/workqueue.c | 218 ++++++++++----------------- 3 files changed, 89 insertions(+), 158 deletions(-) diff --git a/Documentation/core-api/workqueue.rst b/Documentation/core-api/workqueue.rst index a4c9b9d1905f4..8e541c5d8fa97 100644 --- a/Documentation/core-api/workqueue.rst +++ b/Documentation/core-api/workqueue.rst @@ -220,17 +220,16 @@ resources, scheduled and executed. ``max_active`` -------------- -``@max_active`` determines the maximum number of execution contexts -per CPU which can be assigned to the work items of a wq. For example, -with ``@max_active`` of 16, at most 16 work items of the wq can be -executing at the same time per CPU. - -Currently, for a bound wq, the maximum limit for ``@max_active`` is -512 and the default value used when 0 is specified is 256. For an -unbound wq, the limit is higher of 512 and 4 * -``num_possible_cpus()``. These values are chosen sufficiently high -such that they are not the limiting factor while providing protection -in runaway cases. +``@max_active`` determines the maximum number of execution contexts per +CPU which can be assigned to the work items of a wq. For example, with +``@max_active`` of 16, at most 16 work items of the wq can be executing +at the same time per CPU. This is always a per-CPU attribute, even for +unbound workqueues. + +The maximum limit for ``@max_active`` is 512 and the default value used +when 0 is specified is 256. These values are chosen sufficiently high +such that they are not the limiting factor while providing protection in +runaway cases. The number of active work items of a wq is usually regulated by the users of the wq, more specifically, by how many work items the users diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 1a4223cbdb5f2..52d1a6225b445 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -343,14 +343,10 @@ enum { __WQ_ORDERED_EXPLICIT = 1 << 19, /* internal: alloc_ordered_workqueue() */ WQ_MAX_ACTIVE = 512, /* I like 512, better ideas? */ - WQ_MAX_UNBOUND_PER_CPU = 4, /* 4 * #cpus for unbound wq */ + WQ_UNBOUND_MAX_ACTIVE = WQ_MAX_ACTIVE, WQ_DFL_ACTIVE = WQ_MAX_ACTIVE / 2, }; -/* unbound wq's aren't per-cpu, scale max_active according to #cpus */ -#define WQ_UNBOUND_MAX_ACTIVE \ - max_t(int, WQ_MAX_ACTIVE, num_possible_cpus() * WQ_MAX_UNBOUND_PER_CPU) - /* * System-wide workqueues which are always present. * @@ -391,7 +387,7 @@ extern struct workqueue_struct *system_freezable_power_efficient_wq; * alloc_workqueue - allocate a workqueue * @fmt: printf format for the name of the workqueue * @flags: WQ_* flags - * @max_active: max in-flight work items, 0 for default + * @max_active: max in-flight work items per CPU, 0 for default * remaining args: args for @fmt * * Allocate a workqueue with the specified parameters. For detailed diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 9f4341885f60c..48208888aee09 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -321,8 +321,7 @@ struct workqueue_struct { /* hot fields used during command issue, aligned to cacheline */ unsigned int flags ____cacheline_aligned; /* WQ: WQ_* flags */ - struct pool_workqueue __percpu **cpu_pwq; /* I: per-cpu pwqs */ - struct pool_workqueue __rcu *numa_pwq_tbl[]; /* PWR: unbound pwqs indexed by node */ + struct pool_workqueue __percpu __rcu **cpu_pwq; /* I: per-cpu pwqs */ }; static struct kmem_cache *pwq_cache; @@ -608,35 +607,6 @@ static int worker_pool_assign_id(struct worker_pool *pool) return ret; } -/** - * unbound_pwq_by_node - return the unbound pool_workqueue for the given node - * @wq: the target workqueue - * @node: the node ID - * - * This must be called with any of wq_pool_mutex, wq->mutex or RCU - * read locked. - * If the pwq needs to be used beyond the locking in effect, the caller is - * responsible for guaranteeing that the pwq stays online. - * - * Return: The unbound pool_workqueue for @node. - */ -static struct pool_workqueue *unbound_pwq_by_node(struct workqueue_struct *wq, - int node) -{ - assert_rcu_or_wq_mutex_or_pool_mutex(wq); - - /* - * XXX: @node can be NUMA_NO_NODE if CPU goes offline while a - * delayed item is pending. The plan is to keep CPU -> NODE - * mapping valid and stable across CPU on/offlines. Once that - * happens, this workaround can be removed. - */ - if (unlikely(node == NUMA_NO_NODE)) - return wq->dfl_pwq; - - return rcu_dereference_raw(wq->numa_pwq_tbl[node]); -} - static unsigned int work_color_to_flags(int color) { return color << WORK_STRUCT_COLOR_SHIFT; @@ -1676,16 +1646,14 @@ static void __queue_work(int cpu, struct workqueue_struct *wq, rcu_read_lock(); retry: /* pwq which will be used unless @work is executing elsewhere */ - if (wq->flags & WQ_UNBOUND) { - if (req_cpu == WORK_CPU_UNBOUND) + if (req_cpu == WORK_CPU_UNBOUND) { + if (wq->flags & WQ_UNBOUND) cpu = wq_select_unbound_cpu(raw_smp_processor_id()); - pwq = unbound_pwq_by_node(wq, cpu_to_node(cpu)); - } else { - if (req_cpu == WORK_CPU_UNBOUND) + else cpu = raw_smp_processor_id(); - pwq = *per_cpu_ptr(wq->cpu_pwq, cpu); } + pwq = rcu_dereference(*per_cpu_ptr(wq->cpu_pwq, cpu)); pool = pwq->pool; /* @@ -1715,12 +1683,11 @@ retry: } /* - * pwq is determined and locked. For unbound pools, we could have - * raced with pwq release and it could already be dead. If its - * refcnt is zero, repeat pwq selection. Note that pwqs never die - * without another pwq replacing it in the numa_pwq_tbl or while - * work items are executing on it, so the retrying is guaranteed to - * make forward-progress. + * pwq is determined and locked. For unbound pools, we could have raced + * with pwq release and it could already be dead. If its refcnt is zero, + * repeat pwq selection. Note that unbound pwqs never die without + * another pwq replacing it in cpu_pwq or while work items are executing + * on it, so the retrying is guaranteed to make forward-progress. */ if (unlikely(!pwq->refcnt)) { if (wq->flags & WQ_UNBOUND) { @@ -3818,12 +3785,8 @@ static void rcu_free_wq(struct rcu_head *rcu) container_of(rcu, struct workqueue_struct, rcu); wq_free_lockdep(wq); - - if (!(wq->flags & WQ_UNBOUND)) - free_percpu(wq->cpu_pwq); - else - free_workqueue_attrs(wq->unbound_attrs); - + free_percpu(wq->cpu_pwq); + free_workqueue_attrs(wq->unbound_attrs); kfree(wq); } @@ -4174,11 +4137,8 @@ static struct pool_workqueue *alloc_unbound_pwq(struct workqueue_struct *wq, * * The caller is responsible for ensuring that the cpumask of @node stays * stable. - * - * Return: %true if the resulting @cpumask is different from @attrs->cpumask, - * %false if equal. */ -static bool wq_calc_node_cpumask(const struct workqueue_attrs *attrs, int node, +static void wq_calc_node_cpumask(const struct workqueue_attrs *attrs, int node, int cpu_going_down, cpumask_t *cpumask) { if (!wq_numa_enabled || attrs->no_numa) @@ -4195,23 +4155,18 @@ static bool wq_calc_node_cpumask(const struct workqueue_attrs *attrs, int node, /* yeap, return possible CPUs in @node that @attrs wants */ cpumask_and(cpumask, attrs->cpumask, wq_numa_possible_cpumask[node]); - if (cpumask_empty(cpumask)) { + if (cpumask_empty(cpumask)) pr_warn_once("WARNING: workqueue cpumask: online intersect > " "possible intersect\n"); - return false; - } - - return !cpumask_equal(cpumask, attrs->cpumask); + return; use_dfl: cpumask_copy(cpumask, attrs->cpumask); - return false; } -/* install @pwq into @wq's numa_pwq_tbl[] for @node and return the old pwq */ -static struct pool_workqueue *numa_pwq_tbl_install(struct workqueue_struct *wq, - int node, - struct pool_workqueue *pwq) +/* install @pwq into @wq's cpu_pwq and return the old pwq */ +static struct pool_workqueue *install_unbound_pwq(struct workqueue_struct *wq, + int cpu, struct pool_workqueue *pwq) { struct pool_workqueue *old_pwq; @@ -4221,8 +4176,8 @@ static struct pool_workqueue *numa_pwq_tbl_install(struct workqueue_struct *wq, /* link_pwq() can handle duplicate calls */ link_pwq(pwq); - old_pwq = rcu_access_pointer(wq->numa_pwq_tbl[node]); - rcu_assign_pointer(wq->numa_pwq_tbl[node], pwq); + old_pwq = rcu_access_pointer(*per_cpu_ptr(wq->cpu_pwq, cpu)); + rcu_assign_pointer(*per_cpu_ptr(wq->cpu_pwq, cpu), pwq); return old_pwq; } @@ -4239,10 +4194,10 @@ struct apply_wqattrs_ctx { static void apply_wqattrs_cleanup(struct apply_wqattrs_ctx *ctx) { if (ctx) { - int node; + int cpu; - for_each_node(node) - put_pwq_unlocked(ctx->pwq_tbl[node]); + for_each_possible_cpu(cpu) + put_pwq_unlocked(ctx->pwq_tbl[cpu]); put_pwq_unlocked(ctx->dfl_pwq); free_workqueue_attrs(ctx->attrs); @@ -4259,11 +4214,11 @@ apply_wqattrs_prepare(struct workqueue_struct *wq, { struct apply_wqattrs_ctx *ctx; struct workqueue_attrs *new_attrs, *tmp_attrs; - int node; + int cpu; lockdep_assert_held(&wq_pool_mutex); - ctx = kzalloc(struct_size(ctx, pwq_tbl, nr_node_ids), GFP_KERNEL); + ctx = kzalloc(struct_size(ctx, pwq_tbl, nr_cpu_ids), GFP_KERNEL); new_attrs = alloc_workqueue_attrs(); tmp_attrs = alloc_workqueue_attrs(); @@ -4297,14 +4252,16 @@ apply_wqattrs_prepare(struct workqueue_struct *wq, if (!ctx->dfl_pwq) goto out_free; - for_each_node(node) { - if (wq_calc_node_cpumask(new_attrs, node, -1, tmp_attrs->cpumask)) { - ctx->pwq_tbl[node] = alloc_unbound_pwq(wq, tmp_attrs); - if (!ctx->pwq_tbl[node]) - goto out_free; - } else { + for_each_possible_cpu(cpu) { + if (new_attrs->no_numa) { ctx->dfl_pwq->refcnt++; - ctx->pwq_tbl[node] = ctx->dfl_pwq; + ctx->pwq_tbl[cpu] = ctx->dfl_pwq; + } else { + wq_calc_node_cpumask(new_attrs, cpu_to_node(cpu), -1, + tmp_attrs->cpumask); + ctx->pwq_tbl[cpu] = alloc_unbound_pwq(wq, tmp_attrs); + if (!ctx->pwq_tbl[cpu]) + goto out_free; } } @@ -4327,7 +4284,7 @@ out_free: /* set attrs and install prepared pwqs, @ctx points to old pwqs on return */ static void apply_wqattrs_commit(struct apply_wqattrs_ctx *ctx) { - int node; + int cpu; /* all pwqs have been created successfully, let's install'em */ mutex_lock(&ctx->wq->mutex); @@ -4335,9 +4292,9 @@ static void apply_wqattrs_commit(struct apply_wqattrs_ctx *ctx) copy_workqueue_attrs(ctx->wq->unbound_attrs, ctx->attrs); /* save the previous pwq and install the new one */ - for_each_node(node) - ctx->pwq_tbl[node] = numa_pwq_tbl_install(ctx->wq, node, - ctx->pwq_tbl[node]); + for_each_possible_cpu(cpu) + ctx->pwq_tbl[cpu] = install_unbound_pwq(ctx->wq, cpu, + ctx->pwq_tbl[cpu]); /* @dfl_pwq might not have been used, ensure it's linked */ link_pwq(ctx->dfl_pwq); @@ -4466,20 +4423,13 @@ static void wq_update_unbound_numa(struct workqueue_struct *wq, int cpu, cpumask = target_attrs->cpumask; copy_workqueue_attrs(target_attrs, wq->unbound_attrs); - pwq = unbound_pwq_by_node(wq, node); - /* - * Let's determine what needs to be done. If the target cpumask is - * different from the default pwq's, we need to compare it to @pwq's - * and create a new one if they don't match. If the target cpumask - * equals the default pwq's, the default pwq should be used. - */ - if (wq_calc_node_cpumask(wq->dfl_pwq->pool->attrs, node, off_cpu, cpumask)) { - if (cpumask_equal(cpumask, pwq->pool->attrs->cpumask)) - return; - } else { - goto use_dfl_pwq; - } + /* nothing to do if the target cpumask matches the current pwq */ + wq_calc_node_cpumask(wq->dfl_pwq->pool->attrs, node, off_cpu, cpumask); + pwq = rcu_dereference_protected(*per_cpu_ptr(wq->cpu_pwq, cpu), + lockdep_is_held(&wq_pool_mutex)); + if (cpumask_equal(cpumask, pwq->pool->attrs->cpumask)) + return; /* create a new pwq */ pwq = alloc_unbound_pwq(wq, target_attrs); @@ -4491,7 +4441,7 @@ static void wq_update_unbound_numa(struct workqueue_struct *wq, int cpu, /* Install the new pwq. */ mutex_lock(&wq->mutex); - old_pwq = numa_pwq_tbl_install(wq, node, pwq); + old_pwq = install_unbound_pwq(wq, cpu, pwq); goto out_unlock; use_dfl_pwq: @@ -4499,7 +4449,7 @@ use_dfl_pwq: raw_spin_lock_irq(&wq->dfl_pwq->pool->lock); get_pwq(wq->dfl_pwq); raw_spin_unlock_irq(&wq->dfl_pwq->pool->lock); - old_pwq = numa_pwq_tbl_install(wq, node, wq->dfl_pwq); + old_pwq = install_unbound_pwq(wq, cpu, wq->dfl_pwq); out_unlock: mutex_unlock(&wq->mutex); put_pwq_unlocked(old_pwq); @@ -4510,11 +4460,11 @@ static int alloc_and_link_pwqs(struct workqueue_struct *wq) bool highpri = wq->flags & WQ_HIGHPRI; int cpu, ret; - if (!(wq->flags & WQ_UNBOUND)) { - wq->cpu_pwq = alloc_percpu(struct pool_workqueue *); - if (!wq->cpu_pwq) - goto enomem; + wq->cpu_pwq = alloc_percpu(struct pool_workqueue *); + if (!wq->cpu_pwq) + goto enomem; + if (!(wq->flags & WQ_UNBOUND)) { for_each_possible_cpu(cpu) { struct pool_workqueue **pwq_p = per_cpu_ptr(wq->cpu_pwq, cpu); @@ -4562,13 +4512,11 @@ enomem: static int wq_clamp_max_active(int max_active, unsigned int flags, const char *name) { - int lim = flags & WQ_UNBOUND ? WQ_UNBOUND_MAX_ACTIVE : WQ_MAX_ACTIVE; - - if (max_active < 1 || max_active > lim) + if (max_active < 1 || max_active > WQ_MAX_ACTIVE) pr_warn("workqueue: max_active %d requested for %s is out of range, clamping between %d and %d\n", - max_active, name, 1, lim); + max_active, name, 1, WQ_MAX_ACTIVE); - return clamp_val(max_active, 1, lim); + return clamp_val(max_active, 1, WQ_MAX_ACTIVE); } /* @@ -4612,7 +4560,6 @@ struct workqueue_struct *alloc_workqueue(const char *fmt, unsigned int flags, int max_active, ...) { - size_t tbl_size = 0; va_list args; struct workqueue_struct *wq; struct pool_workqueue *pwq; @@ -4632,10 +4579,7 @@ struct workqueue_struct *alloc_workqueue(const char *fmt, flags |= WQ_UNBOUND; /* allocate wq and format name */ - if (flags & WQ_UNBOUND) - tbl_size = nr_node_ids * sizeof(wq->numa_pwq_tbl[0]); - - wq = kzalloc(sizeof(*wq) + tbl_size, GFP_KERNEL); + wq = kzalloc(sizeof(*wq), GFP_KERNEL); if (!wq) return NULL; @@ -4730,7 +4674,7 @@ static bool pwq_busy(struct pool_workqueue *pwq) void destroy_workqueue(struct workqueue_struct *wq) { struct pool_workqueue *pwq; - int cpu, node; + int cpu; /* * Remove it from sysfs first so that sanity check failure doesn't @@ -4789,29 +4733,23 @@ void destroy_workqueue(struct workqueue_struct *wq) list_del_rcu(&wq->list); mutex_unlock(&wq_pool_mutex); - if (!(wq->flags & WQ_UNBOUND)) { - for_each_possible_cpu(cpu) - put_pwq_unlocked(*per_cpu_ptr(wq->cpu_pwq, cpu)); - } else { - /* - * We're the sole accessor of @wq at this point. Directly - * access numa_pwq_tbl[] and dfl_pwq to put the base refs. - * @wq will be freed when the last pwq is released. - */ - for_each_node(node) { - pwq = rcu_access_pointer(wq->numa_pwq_tbl[node]); - RCU_INIT_POINTER(wq->numa_pwq_tbl[node], NULL); - put_pwq_unlocked(pwq); - } + /* + * We're the sole accessor of @wq. Directly access cpu_pwq and dfl_pwq + * to put the base refs. @wq will be auto-destroyed from the last + * pwq_put. RCU read lock prevents @wq from going away from under us. + */ + rcu_read_lock(); - /* - * Put dfl_pwq. @wq may be freed any time after dfl_pwq is - * put. Don't access it afterwards. - */ - pwq = wq->dfl_pwq; - wq->dfl_pwq = NULL; + for_each_possible_cpu(cpu) { + pwq = rcu_access_pointer(*per_cpu_ptr(wq->cpu_pwq, cpu)); + RCU_INIT_POINTER(*per_cpu_ptr(wq->cpu_pwq, cpu), NULL); put_pwq_unlocked(pwq); } + + put_pwq_unlocked(wq->dfl_pwq); + wq->dfl_pwq = NULL; + + rcu_read_unlock(); } EXPORT_SYMBOL_GPL(destroy_workqueue); @@ -4888,10 +4826,11 @@ bool current_is_workqueue_rescuer(void) * unreliable and only useful as advisory hints or for debugging. * * If @cpu is WORK_CPU_UNBOUND, the test is performed on the local CPU. - * Note that both per-cpu and unbound workqueues may be associated with - * multiple pool_workqueues which have separate congested states. A - * workqueue being congested on one CPU doesn't mean the workqueue is also - * contested on other CPUs / NUMA nodes. + * + * With the exception of ordered workqueues, all workqueues have per-cpu + * pool_workqueues, each with its own congested state. A workqueue being + * congested on one CPU doesn't mean that the workqueue is contested on any + * other CPUs. * * Return: * %true if congested, %false otherwise. @@ -4907,12 +4846,9 @@ bool workqueue_congested(int cpu, struct workqueue_struct *wq) if (cpu == WORK_CPU_UNBOUND) cpu = smp_processor_id(); - if (!(wq->flags & WQ_UNBOUND)) - pwq = *per_cpu_ptr(wq->cpu_pwq, cpu); - else - pwq = unbound_pwq_by_node(wq, cpu_to_node(cpu)); - + pwq = *per_cpu_ptr(wq->cpu_pwq, cpu); ret = !list_empty(&pwq->inactive_works); + preempt_enable(); rcu_read_unlock(); @@ -6434,7 +6370,7 @@ void __init workqueue_init_early(void) system_highpri_wq = alloc_workqueue("events_highpri", WQ_HIGHPRI, 0); system_long_wq = alloc_workqueue("events_long", 0, 0); system_unbound_wq = alloc_workqueue("events_unbound", WQ_UNBOUND, - WQ_UNBOUND_MAX_ACTIVE); + WQ_MAX_ACTIVE); system_freezable_wq = alloc_workqueue("events_freezable", WQ_FREEZABLE, 0); system_power_efficient_wq = alloc_workqueue("events_power_efficient", -- GitLab From af73f5c9febe5095ee492ae43e9898fca65ced70 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:23 -1000 Subject: [PATCH 0885/3445] workqueue: Rename workqueue_attrs->no_numa to ->ordered With the recent removal of NUMA related module param and sysfs knob, workqueue_attrs->no_numa is now only used to implement ordered workqueues. Let's rename the field so that it's less confusing especially with the planned CPU affinity awareness improvements. Just a rename. No functional changes. Signed-off-by: Tejun Heo --- include/linux/workqueue.h | 6 +++--- kernel/workqueue.c | 19 +++++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 52d1a6225b445..f0c10f491b15a 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -142,13 +142,13 @@ struct workqueue_attrs { cpumask_var_t cpumask; /** - * @no_numa: disable NUMA affinity + * @ordered: work items must be executed one by one in queueing order * - * Unlike other fields, ``no_numa`` isn't a property of a worker_pool. It + * Unlike other fields, ``ordered`` isn't a property of a worker_pool. It * only modifies how :c:func:`apply_workqueue_attrs` select pools and thus * doesn't participate in pool hash calculations or equality comparisons. */ - bool no_numa; + bool ordered; }; static inline struct delayed_work *to_delayed_work(struct work_struct *work) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 48208888aee09..82413df1c120c 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -3672,10 +3672,10 @@ static void copy_workqueue_attrs(struct workqueue_attrs *to, cpumask_copy(to->cpumask, from->cpumask); /* * Unlike hash and equality test, this function doesn't ignore - * ->no_numa as it is used for both pool and wq attrs. Instead, - * get_unbound_pool() explicitly clears ->no_numa after copying. + * ->ordered as it is used for both pool and wq attrs. Instead, + * get_unbound_pool() explicitly clears ->ordered after copying. */ - to->no_numa = from->no_numa; + to->ordered = from->ordered; } /* hash value of the content of @attr */ @@ -3933,10 +3933,10 @@ static struct worker_pool *get_unbound_pool(const struct workqueue_attrs *attrs) pool->node = target_node; /* - * no_numa isn't a worker_pool attribute, always clear it. See + * ordered isn't a worker_pool attribute, always clear it. See * 'struct workqueue_attrs' comments for detail. */ - pool->attrs->no_numa = false; + pool->attrs->ordered = false; if (worker_pool_assign_id(pool) < 0) goto fail; @@ -4141,7 +4141,7 @@ static struct pool_workqueue *alloc_unbound_pwq(struct workqueue_struct *wq, static void wq_calc_node_cpumask(const struct workqueue_attrs *attrs, int node, int cpu_going_down, cpumask_t *cpumask) { - if (!wq_numa_enabled || attrs->no_numa) + if (!wq_numa_enabled || attrs->ordered) goto use_dfl; /* does @node have any online CPUs @attrs wants? */ @@ -4253,7 +4253,7 @@ apply_wqattrs_prepare(struct workqueue_struct *wq, goto out_free; for_each_possible_cpu(cpu) { - if (new_attrs->no_numa) { + if (new_attrs->ordered) { ctx->dfl_pwq->refcnt++; ctx->pwq_tbl[cpu] = ctx->dfl_pwq; } else { @@ -4411,7 +4411,7 @@ static void wq_update_unbound_numa(struct workqueue_struct *wq, int cpu, lockdep_assert_held(&wq_pool_mutex); if (!wq_numa_enabled || !(wq->flags & WQ_UNBOUND) || - wq->unbound_attrs->no_numa) + wq->unbound_attrs->ordered) return; /* @@ -6358,11 +6358,10 @@ void __init workqueue_init_early(void) /* * An ordered wq should have only one pwq as ordering is * guaranteed by max_active which is enforced by pwqs. - * Turn off NUMA so that dfl_pwq is used for all nodes. */ BUG_ON(!(attrs = alloc_workqueue_attrs())); attrs->nice = std_nice[i]; - attrs->no_numa = true; + attrs->ordered = true; ordered_wq_attrs[i] = attrs; } -- GitLab From fef59c9cab6ac5592da54f6c2b1195418f14e4d0 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:23 -1000 Subject: [PATCH 0886/3445] workqueue: Rename NUMA related names to use pod instead Workqueue is in the process of improving CPU affinity awareness. It will become more flexible and won't be tied to NUMA node boundaries. This patch renames all NUMA related names in workqueue.c to use "pod" instead. While "pod" isn't a very common term, it short and captures the grouping of CPUs well enough. These names are only going to be used within workqueue implementation proper, so the specific naming doesn't matter that much. * wq_numa_possible_cpumask -> wq_pod_cpus * wq_numa_enabled -> wq_pod_enabled * wq_update_unbound_numa_attrs_buf -> wq_update_pod_attrs_buf * workqueue_select_cpu_near -> select_numa_node_cpu This rename is different from others. The function is only used by queue_work_node() and specifically tries to find a CPU in the specified NUMA node. As workqueue affinity will become more flexible and untied from NUMA, this function's name should specifically describe that it's for NUMA. * wq_calc_node_cpumask -> wq_calc_pod_cpumask * wq_update_unbound_numa -> wq_update_pod * wq_numa_init -> wq_pod_init * node -> pod in local variables Only renames. No functional changes. Signed-off-by: Tejun Heo --- kernel/workqueue.c | 161 +++++++++++++++++++++------------------------ 1 file changed, 76 insertions(+), 85 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 82413df1c120c..8a484f606e74d 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -326,8 +326,7 @@ struct workqueue_struct { static struct kmem_cache *pwq_cache; -static cpumask_var_t *wq_numa_possible_cpumask; - /* possible CPUs of each node */ +static cpumask_var_t *wq_pod_cpus; /* possible CPUs of each node */ /* * Per-cpu work items which run for longer than the following threshold are @@ -345,10 +344,10 @@ module_param_named(power_efficient, wq_power_efficient, bool, 0444); static bool wq_online; /* can kworkers be created yet? */ -static bool wq_numa_enabled; /* unbound NUMA affinity enabled */ +static bool wq_pod_enabled; /* unbound CPU pod affinity enabled */ -/* buf for wq_update_unbound_numa_attrs(), protected by CPU hotplug exclusion */ -static struct workqueue_attrs *wq_update_unbound_numa_attrs_buf; +/* buf for wq_update_unbound_pod_attrs(), protected by CPU hotplug exclusion */ +static struct workqueue_attrs *wq_update_pod_attrs_buf; static DEFINE_MUTEX(wq_pool_mutex); /* protects pools and workqueues list */ static DEFINE_MUTEX(wq_pool_attach_mutex); /* protects worker attach/detach */ @@ -1762,7 +1761,7 @@ bool queue_work_on(int cpu, struct workqueue_struct *wq, EXPORT_SYMBOL(queue_work_on); /** - * workqueue_select_cpu_near - Select a CPU based on NUMA node + * select_numa_node_cpu - Select a CPU based on NUMA node * @node: NUMA node ID that we want to select a CPU from * * This function will attempt to find a "random" cpu available on a given @@ -1770,12 +1769,12 @@ EXPORT_SYMBOL(queue_work_on); * WORK_CPU_UNBOUND indicating that we should just schedule to any * available CPU if we need to schedule this work. */ -static int workqueue_select_cpu_near(int node) +static int select_numa_node_cpu(int node) { int cpu; /* No point in doing this if NUMA isn't enabled for workqueues */ - if (!wq_numa_enabled) + if (!wq_pod_enabled) return WORK_CPU_UNBOUND; /* Delay binding to CPU if node is not valid or online */ @@ -1834,7 +1833,7 @@ bool queue_work_node(int node, struct workqueue_struct *wq, local_irq_save(flags); if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) { - int cpu = workqueue_select_cpu_near(node); + int cpu = select_numa_node_cpu(node); __queue_work(cpu, wq, work); ret = true; @@ -3900,8 +3899,8 @@ static struct worker_pool *get_unbound_pool(const struct workqueue_attrs *attrs) { u32 hash = wqattrs_hash(attrs); struct worker_pool *pool; - int node; - int target_node = NUMA_NO_NODE; + int pod; + int target_pod = NUMA_NO_NODE; lockdep_assert_held(&wq_pool_mutex); @@ -3913,24 +3912,23 @@ static struct worker_pool *get_unbound_pool(const struct workqueue_attrs *attrs) } } - /* if cpumask is contained inside a NUMA node, we belong to that node */ - if (wq_numa_enabled) { - for_each_node(node) { - if (cpumask_subset(attrs->cpumask, - wq_numa_possible_cpumask[node])) { - target_node = node; + /* if cpumask is contained inside a pod, we belong to that pod */ + if (wq_pod_enabled) { + for_each_node(pod) { + if (cpumask_subset(attrs->cpumask, wq_pod_cpus[pod])) { + target_pod = pod; break; } } } /* nope, create a new one */ - pool = kzalloc_node(sizeof(*pool), GFP_KERNEL, target_node); + pool = kzalloc_node(sizeof(*pool), GFP_KERNEL, target_pod); if (!pool || init_worker_pool(pool) < 0) goto fail; copy_workqueue_attrs(pool->attrs, attrs); - pool->node = target_node; + pool->node = target_pod; /* * ordered isn't a worker_pool attribute, always clear it. See @@ -4120,40 +4118,38 @@ static struct pool_workqueue *alloc_unbound_pwq(struct workqueue_struct *wq, } /** - * wq_calc_node_cpumask - calculate a wq_attrs' cpumask for the specified node + * wq_calc_pod_cpumask - calculate a wq_attrs' cpumask for a pod * @attrs: the wq_attrs of the default pwq of the target workqueue - * @node: the target NUMA node + * @pod: the target CPU pod * @cpu_going_down: if >= 0, the CPU to consider as offline * @cpumask: outarg, the resulting cpumask * - * Calculate the cpumask a workqueue with @attrs should use on @node. If - * @cpu_going_down is >= 0, that cpu is considered offline during - * calculation. The result is stored in @cpumask. + * Calculate the cpumask a workqueue with @attrs should use on @pod. If + * @cpu_going_down is >= 0, that cpu is considered offline during calculation. + * The result is stored in @cpumask. * - * If NUMA affinity is not enabled, @attrs->cpumask is always used. If - * enabled and @node has online CPUs requested by @attrs, the returned - * cpumask is the intersection of the possible CPUs of @node and - * @attrs->cpumask. + * If pod affinity is not enabled, @attrs->cpumask is always used. If enabled + * and @pod has online CPUs requested by @attrs, the returned cpumask is the + * intersection of the possible CPUs of @pod and @attrs->cpumask. * - * The caller is responsible for ensuring that the cpumask of @node stays - * stable. + * The caller is responsible for ensuring that the cpumask of @pod stays stable. */ -static void wq_calc_node_cpumask(const struct workqueue_attrs *attrs, int node, +static void wq_calc_pod_cpumask(const struct workqueue_attrs *attrs, int pod, int cpu_going_down, cpumask_t *cpumask) { - if (!wq_numa_enabled || attrs->ordered) + if (!wq_pod_enabled || attrs->ordered) goto use_dfl; - /* does @node have any online CPUs @attrs wants? */ - cpumask_and(cpumask, cpumask_of_node(node), attrs->cpumask); + /* does @pod have any online CPUs @attrs wants? */ + cpumask_and(cpumask, cpumask_of_node(pod), attrs->cpumask); if (cpu_going_down >= 0) cpumask_clear_cpu(cpu_going_down, cpumask); if (cpumask_empty(cpumask)) goto use_dfl; - /* yeap, return possible CPUs in @node that @attrs wants */ - cpumask_and(cpumask, attrs->cpumask, wq_numa_possible_cpumask[node]); + /* yeap, return possible CPUs in @pod that @attrs wants */ + cpumask_and(cpumask, attrs->cpumask, wq_pod_cpus[pod]); if (cpumask_empty(cpumask)) pr_warn_once("WARNING: workqueue cpumask: online intersect > " @@ -4257,8 +4253,8 @@ apply_wqattrs_prepare(struct workqueue_struct *wq, ctx->dfl_pwq->refcnt++; ctx->pwq_tbl[cpu] = ctx->dfl_pwq; } else { - wq_calc_node_cpumask(new_attrs, cpu_to_node(cpu), -1, - tmp_attrs->cpumask); + wq_calc_pod_cpumask(new_attrs, cpu_to_node(cpu), -1, + tmp_attrs->cpumask); ctx->pwq_tbl[cpu] = alloc_unbound_pwq(wq, tmp_attrs); if (!ctx->pwq_tbl[cpu]) goto out_free; @@ -4349,12 +4345,11 @@ static int apply_workqueue_attrs_locked(struct workqueue_struct *wq, * @wq: the target workqueue * @attrs: the workqueue_attrs to apply, allocated with alloc_workqueue_attrs() * - * Apply @attrs to an unbound workqueue @wq. Unless disabled, on NUMA - * machines, this function maps a separate pwq to each NUMA node with - * possibles CPUs in @attrs->cpumask so that work items are affine to the - * NUMA node it was issued on. Older pwqs are released as in-flight work - * items finish. Note that a work item which repeatedly requeues itself - * back-to-back will stay on its current pwq. + * Apply @attrs to an unbound workqueue @wq. Unless disabled, this function maps + * a separate pwq to each CPU pod with possibles CPUs in @attrs->cpumask so that + * work items are affine to the pod it was issued on. Older pwqs are released as + * in-flight work items finish. Note that a work item which repeatedly requeues + * itself back-to-back will stay on its current pwq. * * Performs GFP_KERNEL allocations. * @@ -4377,32 +4372,31 @@ int apply_workqueue_attrs(struct workqueue_struct *wq, } /** - * wq_update_unbound_numa - update NUMA affinity of a wq for CPU hot[un]plug + * wq_update_pod - update pod affinity of a wq for CPU hot[un]plug * @wq: the target workqueue * @cpu: the CPU to update pool association for * @hotplug_cpu: the CPU coming up or going down * @online: whether @cpu is coming up or going down * * This function is to be called from %CPU_DOWN_PREPARE, %CPU_ONLINE and - * %CPU_DOWN_FAILED. @cpu is being hot[un]plugged, update NUMA affinity of + * %CPU_DOWN_FAILED. @cpu is being hot[un]plugged, update pod affinity of * @wq accordingly. * - * If NUMA affinity can't be adjusted due to memory allocation failure, it - * falls back to @wq->dfl_pwq which may not be optimal but is always - * correct. - * - * Note that when the last allowed CPU of a NUMA node goes offline for a - * workqueue with a cpumask spanning multiple nodes, the workers which were - * already executing the work items for the workqueue will lose their CPU - * affinity and may execute on any CPU. This is similar to how per-cpu - * workqueues behave on CPU_DOWN. If a workqueue user wants strict - * affinity, it's the user's responsibility to flush the work item from - * CPU_DOWN_PREPARE. + * + * If pod affinity can't be adjusted due to memory allocation failure, it falls + * back to @wq->dfl_pwq which may not be optimal but is always correct. + * + * Note that when the last allowed CPU of a pod goes offline for a workqueue + * with a cpumask spanning multiple pods, the workers which were already + * executing the work items for the workqueue will lose their CPU affinity and + * may execute on any CPU. This is similar to how per-cpu workqueues behave on + * CPU_DOWN. If a workqueue user wants strict affinity, it's the user's + * responsibility to flush the work item from CPU_DOWN_PREPARE. */ -static void wq_update_unbound_numa(struct workqueue_struct *wq, int cpu, - int hotplug_cpu, bool online) +static void wq_update_pod(struct workqueue_struct *wq, int cpu, + int hotplug_cpu, bool online) { - int node = cpu_to_node(cpu); + int pod = cpu_to_node(cpu); int off_cpu = online ? -1 : hotplug_cpu; struct pool_workqueue *old_pwq = NULL, *pwq; struct workqueue_attrs *target_attrs; @@ -4410,7 +4404,7 @@ static void wq_update_unbound_numa(struct workqueue_struct *wq, int cpu, lockdep_assert_held(&wq_pool_mutex); - if (!wq_numa_enabled || !(wq->flags & WQ_UNBOUND) || + if (!wq_pod_enabled || !(wq->flags & WQ_UNBOUND) || wq->unbound_attrs->ordered) return; @@ -4419,13 +4413,13 @@ static void wq_update_unbound_numa(struct workqueue_struct *wq, int cpu, * Let's use a preallocated one. The following buf is protected by * CPU hotplug exclusion. */ - target_attrs = wq_update_unbound_numa_attrs_buf; + target_attrs = wq_update_pod_attrs_buf; cpumask = target_attrs->cpumask; copy_workqueue_attrs(target_attrs, wq->unbound_attrs); /* nothing to do if the target cpumask matches the current pwq */ - wq_calc_node_cpumask(wq->dfl_pwq->pool->attrs, node, off_cpu, cpumask); + wq_calc_pod_cpumask(wq->dfl_pwq->pool->attrs, pod, off_cpu, cpumask); pwq = rcu_dereference_protected(*per_cpu_ptr(wq->cpu_pwq, cpu), lockdep_is_held(&wq_pool_mutex)); if (cpumask_equal(cpumask, pwq->pool->attrs->cpumask)) @@ -4434,7 +4428,7 @@ static void wq_update_unbound_numa(struct workqueue_struct *wq, int cpu, /* create a new pwq */ pwq = alloc_unbound_pwq(wq, target_attrs); if (!pwq) { - pr_warn("workqueue: allocation failed while updating NUMA affinity of \"%s\"\n", + pr_warn("workqueue: allocation failed while updating CPU pod affinity of \"%s\"\n", wq->name); goto use_dfl_pwq; } @@ -4565,11 +4559,10 @@ struct workqueue_struct *alloc_workqueue(const char *fmt, struct pool_workqueue *pwq; /* - * Unbound && max_active == 1 used to imply ordered, which is no - * longer the case on NUMA machines due to per-node pools. While + * Unbound && max_active == 1 used to imply ordered, which is no longer + * the case on many machines due to per-pod pools. While * alloc_ordered_workqueue() is the right way to create an ordered - * workqueue, keep the previous behavior to avoid subtle breakages - * on NUMA. + * workqueue, keep the previous behavior to avoid subtle breakages. */ if ((flags & WQ_UNBOUND) && max_active == 1) flags |= __WQ_ORDERED; @@ -5450,13 +5443,13 @@ int workqueue_online_cpu(unsigned int cpu) mutex_unlock(&wq_pool_attach_mutex); } - /* update NUMA affinity of unbound workqueues */ + /* update pod affinity of unbound workqueues */ list_for_each_entry(wq, &workqueues, list) { int tcpu; for_each_possible_cpu(tcpu) { if (cpu_to_node(tcpu) == cpu_to_node(cpu)) { - wq_update_unbound_numa(wq, tcpu, cpu, true); + wq_update_pod(wq, tcpu, cpu, true); } } } @@ -5475,14 +5468,14 @@ int workqueue_offline_cpu(unsigned int cpu) unbind_workers(cpu); - /* update NUMA affinity of unbound workqueues */ + /* update pod affinity of unbound workqueues */ mutex_lock(&wq_pool_mutex); list_for_each_entry(wq, &workqueues, list) { int tcpu; for_each_possible_cpu(tcpu) { if (cpu_to_node(tcpu) == cpu_to_node(cpu)) { - wq_update_unbound_numa(wq, tcpu, cpu, false); + wq_update_pod(wq, tcpu, cpu, false); } } } @@ -6263,7 +6256,7 @@ static inline void wq_watchdog_init(void) { } #endif /* CONFIG_WQ_WATCHDOG */ -static void __init wq_numa_init(void) +static void __init wq_pod_init(void) { cpumask_var_t *tbl; int node, cpu; @@ -6278,8 +6271,8 @@ static void __init wq_numa_init(void) } } - wq_update_unbound_numa_attrs_buf = alloc_workqueue_attrs(); - BUG_ON(!wq_update_unbound_numa_attrs_buf); + wq_update_pod_attrs_buf = alloc_workqueue_attrs(); + BUG_ON(!wq_update_pod_attrs_buf); /* * We want masks of possible CPUs of each node which isn't readily @@ -6298,8 +6291,8 @@ static void __init wq_numa_init(void) cpumask_set_cpu(cpu, tbl[node]); } - wq_numa_possible_cpumask = tbl; - wq_numa_enabled = true; + wq_pod_cpus = tbl; + wq_pod_enabled = true; } /** @@ -6440,15 +6433,14 @@ void __init workqueue_init(void) wq_cpu_intensive_thresh_init(); /* - * It'd be simpler to initialize NUMA in workqueue_init_early() but - * CPU to node mapping may not be available that early on some - * archs such as power and arm64. As per-cpu pools created - * previously could be missing node hint and unbound pools NUMA - * affinity, fix them up. + * It'd be simpler to initialize pods in workqueue_init_early() but CPU + * to node mapping may not be available that early on some archs such as + * power and arm64. As per-cpu pools created previously could be missing + * node hint and unbound pool pod affinity, fix them up. * * Also, while iterating workqueues, create rescuers if requested. */ - wq_numa_init(); + wq_pod_init(); mutex_lock(&wq_pool_mutex); @@ -6459,8 +6451,7 @@ void __init workqueue_init(void) } list_for_each_entry(wq, &workqueues, list) { - wq_update_unbound_numa(wq, smp_processor_id(), smp_processor_id(), - true); + wq_update_pod(wq, smp_processor_id(), smp_processor_id(), true); WARN(init_rescuer(wq), "workqueue: failed to create early rescuer for %s", wq->name); -- GitLab From a86feae6195ac2148097b063f7fdad8ee1f6dad4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:24 -1000 Subject: [PATCH 0887/3445] workqueue: Move wq_pod_init() below workqueue_init() wq_pod_init() is called from workqueue_init() and responsible for initializing unbound CPU pods according to NUMA node. Workqueue is in the process of improving affinity awareness and wants to use other topology information to initialize unbound CPU pods; however, unlike NUMA nodes, other topology information isn't yet available in workqueue_init(). The next patch will introduce a later stage init function for workqueue which will be responsible for initializing unbound CPU pods. Relocate wq_pod_init() below workqueue_init() where the new init function is going to be located so that the diff can show the content differences. Just a relocation. No functional changes. Signed-off-by: Tejun Heo --- kernel/workqueue.c | 78 ++++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 8a484f606e74d..1e528b7e12c56 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -6256,44 +6256,7 @@ static inline void wq_watchdog_init(void) { } #endif /* CONFIG_WQ_WATCHDOG */ -static void __init wq_pod_init(void) -{ - cpumask_var_t *tbl; - int node, cpu; - - if (num_possible_nodes() <= 1) - return; - - for_each_possible_cpu(cpu) { - if (WARN_ON(cpu_to_node(cpu) == NUMA_NO_NODE)) { - pr_warn("workqueue: NUMA node mapping not available for cpu%d, disabling NUMA support\n", cpu); - return; - } - } - - wq_update_pod_attrs_buf = alloc_workqueue_attrs(); - BUG_ON(!wq_update_pod_attrs_buf); - - /* - * We want masks of possible CPUs of each node which isn't readily - * available. Build one from cpu_to_node() which should have been - * fully initialized by now. - */ - tbl = kcalloc(nr_node_ids, sizeof(tbl[0]), GFP_KERNEL); - BUG_ON(!tbl); - - for_each_node(node) - BUG_ON(!zalloc_cpumask_var_node(&tbl[node], GFP_KERNEL, - node_online(node) ? node : NUMA_NO_NODE)); - - for_each_possible_cpu(cpu) { - node = cpu_to_node(cpu); - cpumask_set_cpu(cpu, tbl[node]); - } - - wq_pod_cpus = tbl; - wq_pod_enabled = true; -} +static void wq_pod_init(void); /** * workqueue_init_early - early init for workqueue subsystem @@ -6474,6 +6437,45 @@ void __init workqueue_init(void) wq_watchdog_init(); } +static void __init wq_pod_init(void) +{ + cpumask_var_t *tbl; + int node, cpu; + + if (num_possible_nodes() <= 1) + return; + + for_each_possible_cpu(cpu) { + if (WARN_ON(cpu_to_node(cpu) == NUMA_NO_NODE)) { + pr_warn("workqueue: NUMA node mapping not available for cpu%d, disabling NUMA support\n", cpu); + return; + } + } + + wq_update_pod_attrs_buf = alloc_workqueue_attrs(); + BUG_ON(!wq_update_pod_attrs_buf); + + /* + * We want masks of possible CPUs of each node which isn't readily + * available. Build one from cpu_to_node() which should have been + * fully initialized by now. + */ + tbl = kcalloc(nr_node_ids, sizeof(tbl[0]), GFP_KERNEL); + BUG_ON(!tbl); + + for_each_node(node) + BUG_ON(!zalloc_cpumask_var_node(&tbl[node], GFP_KERNEL, + node_online(node) ? node : NUMA_NO_NODE)); + + for_each_possible_cpu(cpu) { + node = cpu_to_node(cpu); + cpumask_set_cpu(cpu, tbl[node]); + } + + wq_pod_cpus = tbl; + wq_pod_enabled = true; +} + void __warn_flushing_systemwide_wq(void) { pr_warn("WARNING: Flushing system-wide workqueues will be prohibited in near future.\n"); -- GitLab From 2930155b2e27232c033970f2e110aaac4187cb9e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:24 -1000 Subject: [PATCH 0888/3445] workqueue: Initialize unbound CPU pods later in the boot During boot, to initialize unbound CPU pods, wq_pod_init() was called from workqueue_init(). This is early enough for NUMA nodes to be set up but before SMP is brought up and CPU topology information is populated. Workqueue is in the process of improving CPU locality for unbound workqueues and will need access to topology information during pod init. This adds a new init function workqueue_init_topology() which is called after CPU topology information is available and replaces wq_pod_init(). As unbound CPU pods are now initialized after workqueues are activated, we need to revisit the workqueues to apply the pod configuration. Workqueues which are created before workqueue_init_topology() are set up so that they always use the default worker pool. After pods are set up in workqueue_init_topology(), wq_update_pod() is called on all existing workqueues to update the pool associations accordingly. Note that wq_update_pod_attrs_buf allocation is moved to workqueue_init_early(). This isn't necessary right now but enables further generalization of pod handling in the future. This patch changes the initialization sequence but the end result should be the same. Signed-off-by: Tejun Heo --- include/linux/workqueue.h | 1 + init/main.c | 1 + kernel/workqueue.c | 68 +++++++++++++++++++++++---------------- 3 files changed, 43 insertions(+), 27 deletions(-) diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index f0c10f491b15a..bab9fa3453edd 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -672,5 +672,6 @@ int workqueue_offline_cpu(unsigned int cpu); void __init workqueue_init_early(void); void __init workqueue_init(void); +void __init workqueue_init_topology(void); #endif diff --git a/init/main.c b/init/main.c index ad920fac325c3..436d73261810b 100644 --- a/init/main.c +++ b/init/main.c @@ -1540,6 +1540,7 @@ static noinline void __init kernel_init_freeable(void) smp_init(); sched_init_smp(); + workqueue_init_topology(); padata_init(); page_alloc_init_late(); diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 1e528b7e12c56..5914c820a4f1c 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -6256,17 +6256,15 @@ static inline void wq_watchdog_init(void) { } #endif /* CONFIG_WQ_WATCHDOG */ -static void wq_pod_init(void); - /** * workqueue_init_early - early init for workqueue subsystem * - * This is the first half of two-staged workqueue subsystem initialization - * and invoked as soon as the bare basics - memory allocation, cpumasks and - * idr are up. It sets up all the data structures and system workqueues - * and allows early boot code to create workqueues and queue/cancel work - * items. Actual work item execution starts only after kthreads can be - * created and scheduled right before early initcalls. + * This is the first step of three-staged workqueue subsystem initialization and + * invoked as soon as the bare basics - memory allocation, cpumasks and idr are + * up. It sets up all the data structures and system workqueues and allows early + * boot code to create workqueues and queue/cancel work items. Actual work item + * execution starts only after kthreads can be created and scheduled right + * before early initcalls. */ void __init workqueue_init_early(void) { @@ -6284,6 +6282,9 @@ void __init workqueue_init_early(void) pwq_cache = KMEM_CACHE(pool_workqueue, SLAB_PANIC); + wq_update_pod_attrs_buf = alloc_workqueue_attrs(); + BUG_ON(!wq_update_pod_attrs_buf); + /* initialize CPU pools */ for_each_possible_cpu(cpu) { struct worker_pool *pool; @@ -6381,11 +6382,11 @@ static void __init wq_cpu_intensive_thresh_init(void) /** * workqueue_init - bring workqueue subsystem fully online * - * This is the latter half of two-staged workqueue subsystem initialization - * and invoked as soon as kthreads can be created and scheduled. - * Workqueues have been created and work items queued on them, but there - * are no kworkers executing the work items yet. Populate the worker pools - * with the initial workers and enable future kworker creations. + * This is the second step of three-staged workqueue subsystem initialization + * and invoked as soon as kthreads can be created and scheduled. Workqueues have + * been created and work items queued on them, but there are no kworkers + * executing the work items yet. Populate the worker pools with the initial + * workers and enable future kworker creations. */ void __init workqueue_init(void) { @@ -6395,18 +6396,12 @@ void __init workqueue_init(void) wq_cpu_intensive_thresh_init(); - /* - * It'd be simpler to initialize pods in workqueue_init_early() but CPU - * to node mapping may not be available that early on some archs such as - * power and arm64. As per-cpu pools created previously could be missing - * node hint and unbound pool pod affinity, fix them up. - * - * Also, while iterating workqueues, create rescuers if requested. - */ - wq_pod_init(); - mutex_lock(&wq_pool_mutex); + /* + * Per-cpu pools created earlier could be missing node hint. Fix them + * up. Also, create a rescuer for workqueues that requested it. + */ for_each_possible_cpu(cpu) { for_each_cpu_worker_pool(pool, cpu) { pool->node = cpu_to_node(cpu); @@ -6414,7 +6409,6 @@ void __init workqueue_init(void) } list_for_each_entry(wq, &workqueues, list) { - wq_update_pod(wq, smp_processor_id(), smp_processor_id(), true); WARN(init_rescuer(wq), "workqueue: failed to create early rescuer for %s", wq->name); @@ -6437,8 +6431,16 @@ void __init workqueue_init(void) wq_watchdog_init(); } -static void __init wq_pod_init(void) +/** + * workqueue_init_topology - initialize CPU pods for unbound workqueues + * + * This is the third step of there-staged workqueue subsystem initialization and + * invoked after SMP and topology information are fully initialized. It + * initializes the unbound CPU pods accordingly. + */ +void __init workqueue_init_topology(void) { + struct workqueue_struct *wq; cpumask_var_t *tbl; int node, cpu; @@ -6452,8 +6454,7 @@ static void __init wq_pod_init(void) } } - wq_update_pod_attrs_buf = alloc_workqueue_attrs(); - BUG_ON(!wq_update_pod_attrs_buf); + mutex_lock(&wq_pool_mutex); /* * We want masks of possible CPUs of each node which isn't readily @@ -6474,6 +6475,19 @@ static void __init wq_pod_init(void) wq_pod_cpus = tbl; wq_pod_enabled = true; + + /* + * Workqueues allocated earlier would have all CPUs sharing the default + * worker pool. Explicitly call wq_update_pod() on all workqueue and CPU + * combinations to apply per-pod sharing. + */ + list_for_each_entry(wq, &workqueues, list) { + for_each_online_cpu(cpu) { + wq_update_pod(wq, cpu, cpu, true); + } + } + + mutex_unlock(&wq_pool_mutex); } void __warn_flushing_systemwide_wq(void) -- GitLab From 0f36ee24cd43c67be07166ddd09866dc7a47cb4c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:24 -1000 Subject: [PATCH 0889/3445] workqueue: Factor out actual cpumask calculation to reduce subtlety in wq_update_pod() For an unbound pool, multiple cpumasks are involved. U: The user-specified cpumask (may be filtered with cpu_possible_mask). A: The actual cpumask filtered by wq_unbound_cpumask. If the filtering leaves no CPU, wq_unbound_cpumask is used. P: Per-pod subsets of #A. wq->attrs stores #U, wq->dfl_pwq->pool->attrs->cpumask #A, and wq->cpu_pwq[CPU]->pool->attrs->cpumask #P. wq_update_pod() is called to update per-pod pwq's during CPU hotplug. To calculate the new #P for each workqueue, it needs to call wq_calc_pod_cpumask() with @attrs that contains #A. Currently, wq_update_pod() achieves this by calling wq_calc_pod_cpumask() with wq->dfl_pwq->pool->attrs. This is rather fragile because we're calling wq_calc_pod_cpumask() with @attrs of a worker_pool rather than the workqueue's actual attrs when what we want to calculate is the workqueue's cpumask on the pod. While this works fine currently, future changes will add fields which are used differently between workqueues and worker_pools and this subtlety will bite us. This patch factors out #U -> #A calculation from apply_wqattrs_prepare() into wqattrs_actualize_cpumask and updates wq_update_pod() to copy wq->unbound_attrs and use the new helper to obtain #A freshly instead of abusing wq->dfl_pwq->pool_attrs. This shouldn't cause any behavior changes in the current code. Signed-off-by: Tejun Heo Reported-by: K Prateek Nayak Reference: http://lkml.kernel.org/r/30625cdd-4d61-594b-8db9-6816b017dde3@amd.com --- kernel/workqueue.c | 49 +++++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 5914c820a4f1c..3f1fffa8e6d42 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -348,6 +348,7 @@ static bool wq_pod_enabled; /* unbound CPU pod affinity enabled */ /* buf for wq_update_unbound_pod_attrs(), protected by CPU hotplug exclusion */ static struct workqueue_attrs *wq_update_pod_attrs_buf; +static cpumask_var_t wq_update_pod_cpumask_buf; static DEFINE_MUTEX(wq_pool_mutex); /* protects pools and workqueues list */ static DEFINE_MUTEX(wq_pool_attach_mutex); /* protects worker attach/detach */ @@ -3699,6 +3700,20 @@ static bool wqattrs_equal(const struct workqueue_attrs *a, return true; } +/* Update @attrs with actually available CPUs */ +static void wqattrs_actualize_cpumask(struct workqueue_attrs *attrs, + const cpumask_t *unbound_cpumask) +{ + /* + * Calculate the effective CPU mask of @attrs given @unbound_cpumask. If + * @attrs->cpumask doesn't overlap with @unbound_cpumask, we fallback to + * @unbound_cpumask. + */ + cpumask_and(attrs->cpumask, attrs->cpumask, unbound_cpumask); + if (unlikely(cpumask_empty(attrs->cpumask))) + cpumask_copy(attrs->cpumask, unbound_cpumask); +} + /** * init_worker_pool - initialize a newly zalloc'd worker_pool * @pool: worker_pool to initialize @@ -4221,33 +4236,23 @@ apply_wqattrs_prepare(struct workqueue_struct *wq, if (!ctx || !new_attrs || !tmp_attrs) goto out_free; - /* - * Calculate the attrs of the default pwq with unbound_cpumask - * which is wq_unbound_cpumask or to set to wq_unbound_cpumask. - * If the user configured cpumask doesn't overlap with the - * wq_unbound_cpumask, we fallback to the wq_unbound_cpumask. - */ - copy_workqueue_attrs(new_attrs, attrs); - cpumask_and(new_attrs->cpumask, new_attrs->cpumask, unbound_cpumask); - if (unlikely(cpumask_empty(new_attrs->cpumask))) - cpumask_copy(new_attrs->cpumask, unbound_cpumask); - - /* - * We may create multiple pwqs with differing cpumasks. Make a - * copy of @new_attrs which will be modified and used to obtain - * pools. - */ - copy_workqueue_attrs(tmp_attrs, new_attrs); - /* * If something goes wrong during CPU up/down, we'll fall back to * the default pwq covering whole @attrs->cpumask. Always create * it even if we don't use it immediately. */ + copy_workqueue_attrs(new_attrs, attrs); + wqattrs_actualize_cpumask(new_attrs, unbound_cpumask); ctx->dfl_pwq = alloc_unbound_pwq(wq, new_attrs); if (!ctx->dfl_pwq) goto out_free; + /* + * We may create multiple pwqs with differing cpumasks. Make a copy of + * @new_attrs which will be modified and used to obtain pools. + */ + copy_workqueue_attrs(tmp_attrs, new_attrs); + for_each_possible_cpu(cpu) { if (new_attrs->ordered) { ctx->dfl_pwq->refcnt++; @@ -4414,18 +4419,20 @@ static void wq_update_pod(struct workqueue_struct *wq, int cpu, * CPU hotplug exclusion. */ target_attrs = wq_update_pod_attrs_buf; - cpumask = target_attrs->cpumask; + cpumask = wq_update_pod_cpumask_buf; copy_workqueue_attrs(target_attrs, wq->unbound_attrs); + wqattrs_actualize_cpumask(target_attrs, wq_unbound_cpumask); /* nothing to do if the target cpumask matches the current pwq */ - wq_calc_pod_cpumask(wq->dfl_pwq->pool->attrs, pod, off_cpu, cpumask); + wq_calc_pod_cpumask(target_attrs, pod, off_cpu, cpumask); pwq = rcu_dereference_protected(*per_cpu_ptr(wq->cpu_pwq, cpu), lockdep_is_held(&wq_pool_mutex)); if (cpumask_equal(cpumask, pwq->pool->attrs->cpumask)) return; /* create a new pwq */ + cpumask_copy(target_attrs->cpumask, cpumask); pwq = alloc_unbound_pwq(wq, target_attrs); if (!pwq) { pr_warn("workqueue: allocation failed while updating CPU pod affinity of \"%s\"\n", @@ -6285,6 +6292,8 @@ void __init workqueue_init_early(void) wq_update_pod_attrs_buf = alloc_workqueue_attrs(); BUG_ON(!wq_update_pod_attrs_buf); + BUG_ON(!alloc_cpumask_var(&wq_update_pod_cpumask_buf, GFP_KERNEL)); + /* initialize CPU pools */ for_each_possible_cpu(cpu) { struct worker_pool *pool; -- GitLab From 5de7a03cac14765ba22934b6fb1476456ee36bf8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:24 -1000 Subject: [PATCH 0890/3445] workqueue: Factor out clearing of workqueue-only attrs fields workqueue_attrs can be used for both workqueues and worker_pools. However, some fields, currently only ->ordered, only apply to workqueues and should be cleared to the default / invalid values. Currently, an unbound workqueue explicitly clears attrs->ordered in get_unbound_pool() after copying the source workqueue attrs, while per-cpu workqueues rely on the fact that zeroing on allocation gives us the desired default value for pool->attrs->ordered. This is fragile. Let's add wqattrs_clear_for_pool() which clears attrs->ordered and is called from both init_worker_pool() and get_unbound_pool(). This will ease adding more workqueue-only attrs fields. In get_unbound_pool(), pool->node initialization is moved upwards for readability. This shouldn't cause any behavior changes. Signed-off-by: Tejun Heo --- kernel/workqueue.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 3f1fffa8e6d42..37eab7a1587d7 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -3678,6 +3678,15 @@ static void copy_workqueue_attrs(struct workqueue_attrs *to, to->ordered = from->ordered; } +/* + * Some attrs fields are workqueue-only. Clear them for worker_pool's. See the + * comments in 'struct workqueue_attrs' definition. + */ +static void wqattrs_clear_for_pool(struct workqueue_attrs *attrs) +{ + attrs->ordered = false; +} + /* hash value of the content of @attr */ static u32 wqattrs_hash(const struct workqueue_attrs *attrs) { @@ -3752,6 +3761,9 @@ static int init_worker_pool(struct worker_pool *pool) pool->attrs = alloc_workqueue_attrs(); if (!pool->attrs) return -ENOMEM; + + wqattrs_clear_for_pool(pool->attrs); + return 0; } @@ -3942,14 +3954,10 @@ static struct worker_pool *get_unbound_pool(const struct workqueue_attrs *attrs) if (!pool || init_worker_pool(pool) < 0) goto fail; - copy_workqueue_attrs(pool->attrs, attrs); pool->node = target_pod; - /* - * ordered isn't a worker_pool attribute, always clear it. See - * 'struct workqueue_attrs' comments for detail. - */ - pool->attrs->ordered = false; + copy_workqueue_attrs(pool->attrs, attrs); + wqattrs_clear_for_pool(pool->attrs); if (worker_pool_assign_id(pool) < 0) goto fail; -- GitLab From 84193c07105c62d206fb230b2f29002226628989 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:24 -1000 Subject: [PATCH 0891/3445] workqueue: Generalize unbound CPU pods While renamed to pod, the code still assumes that the pods are defined by NUMA boundaries. Let's generalize it: * workqueue_attrs->affn_scope is added. Each enum represents the type of boundaries that define the pods. There are currently two scopes - WQ_AFFN_NUMA and WQ_AFFN_SYSTEM. The former is the same behavior as before - one pod per NUMA node. The latter defines one global pod across the whole system. * struct wq_pod_type is added which describes how pods are configured for each affnity scope. For each pod, it lists the member CPUs and the preferred NUMA node for memory allocations. The reverse mapping from CPU to pod is also available. * wq_pod_enabled is dropped. Pod is now always enabled. The previously disabled behavior is now implemented through WQ_AFFN_SYSTEM. * get_unbound_pool() wants to determine the NUMA node to allocate memory from for the new pool. The variables are renamed from node to pod but the logic still assumes they're one and the same. Clearly distinguish them - walk the WQ_AFFN_NUMA pods to find the matching pod and then use the pod's NUMA node. * wq_calc_pod_cpumask() was taking @pod but assumed that it was the NUMA node. Take @cpu instead and determine the cpumask to use from the pod_type matching @attrs. * apply_wqattrs_prepare() is update to return ERR_PTR() on error instead of NULL so that it can indicate -EINVAL on invalid affinity scopes. This patch allows CPUs to be grouped into pods however desired per type. While this patch causes some internal behavior changes, nothing material should change for workqueue users. v2: Trigger WARN_ON_ONCE() in wqattrs_pod_type() if affn_scope is WQ_AFFN_NR_TYPES which indicates that the function is called with a worker_pool's attrs instead of a workqueue's. Signed-off-by: Tejun Heo --- include/linux/workqueue.h | 31 ++++++- kernel/workqueue.c | 171 ++++++++++++++++++++++++-------------- 2 files changed, 137 insertions(+), 65 deletions(-) diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index bab9fa3453edd..180491ee6706b 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -125,6 +125,15 @@ struct rcu_work { struct workqueue_struct *wq; }; +enum wq_affn_scope { + WQ_AFFN_NUMA, /* one pod per NUMA node */ + WQ_AFFN_SYSTEM, /* one pod across the whole system */ + + WQ_AFFN_NR_TYPES, + + WQ_AFFN_DFL = WQ_AFFN_NUMA, +}; + /** * struct workqueue_attrs - A struct for workqueue attributes. * @@ -141,12 +150,26 @@ struct workqueue_attrs { */ cpumask_var_t cpumask; + /* + * Below fields aren't properties of a worker_pool. They only modify how + * :c:func:`apply_workqueue_attrs` select pools and thus don't + * participate in pool hash calculations or equality comparisons. + */ + /** - * @ordered: work items must be executed one by one in queueing order + * @affn_scope: unbound CPU affinity scope * - * Unlike other fields, ``ordered`` isn't a property of a worker_pool. It - * only modifies how :c:func:`apply_workqueue_attrs` select pools and thus - * doesn't participate in pool hash calculations or equality comparisons. + * CPU pods are used to improve execution locality of unbound work + * items. There are multiple pod types, one for each wq_affn_scope, and + * every CPU in the system belongs to one pod in every pod type. CPUs + * that belong to the same pod share the worker pool. For example, + * selecting %WQ_AFFN_NUMA makes the workqueue use a separate worker + * pool for each NUMA node. + */ + enum wq_affn_scope affn_scope; + + /** + * @ordered: work items must be executed one by one in queueing order */ bool ordered; }; diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 37eab7a1587d7..6c4d7b1fdf9a1 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -326,7 +326,18 @@ struct workqueue_struct { static struct kmem_cache *pwq_cache; -static cpumask_var_t *wq_pod_cpus; /* possible CPUs of each node */ +/* + * Each pod type describes how CPUs should be grouped for unbound workqueues. + * See the comment above workqueue_attrs->affn_scope. + */ +struct wq_pod_type { + int nr_pods; /* number of pods */ + cpumask_var_t *pod_cpus; /* pod -> cpus */ + int *pod_node; /* pod -> node */ + int *cpu_pod; /* cpu -> pod */ +}; + +static struct wq_pod_type wq_pod_types[WQ_AFFN_NR_TYPES]; /* * Per-cpu work items which run for longer than the following threshold are @@ -344,8 +355,6 @@ module_param_named(power_efficient, wq_power_efficient, bool, 0444); static bool wq_online; /* can kworkers be created yet? */ -static bool wq_pod_enabled; /* unbound CPU pod affinity enabled */ - /* buf for wq_update_unbound_pod_attrs(), protected by CPU hotplug exclusion */ static struct workqueue_attrs *wq_update_pod_attrs_buf; static cpumask_var_t wq_update_pod_cpumask_buf; @@ -1774,10 +1783,6 @@ static int select_numa_node_cpu(int node) { int cpu; - /* No point in doing this if NUMA isn't enabled for workqueues */ - if (!wq_pod_enabled) - return WORK_CPU_UNBOUND; - /* Delay binding to CPU if node is not valid or online */ if (node < 0 || node >= MAX_NUMNODES || !node_online(node)) return WORK_CPU_UNBOUND; @@ -3659,6 +3664,7 @@ struct workqueue_attrs *alloc_workqueue_attrs(void) goto fail; cpumask_copy(attrs->cpumask, cpu_possible_mask); + attrs->affn_scope = WQ_AFFN_DFL; return attrs; fail: free_workqueue_attrs(attrs); @@ -3670,11 +3676,13 @@ static void copy_workqueue_attrs(struct workqueue_attrs *to, { to->nice = from->nice; cpumask_copy(to->cpumask, from->cpumask); + /* - * Unlike hash and equality test, this function doesn't ignore - * ->ordered as it is used for both pool and wq attrs. Instead, - * get_unbound_pool() explicitly clears ->ordered after copying. + * Unlike hash and equality test, copying shouldn't ignore wq-only + * fields as copying is used for both pool and wq attrs. Instead, + * get_unbound_pool() explicitly clears the fields. */ + to->affn_scope = from->affn_scope; to->ordered = from->ordered; } @@ -3684,6 +3692,7 @@ static void copy_workqueue_attrs(struct workqueue_attrs *to, */ static void wqattrs_clear_for_pool(struct workqueue_attrs *attrs) { + attrs->affn_scope = WQ_AFFN_NR_TYPES; attrs->ordered = false; } @@ -3723,6 +3732,25 @@ static void wqattrs_actualize_cpumask(struct workqueue_attrs *attrs, cpumask_copy(attrs->cpumask, unbound_cpumask); } +/* find wq_pod_type to use for @attrs */ +static const struct wq_pod_type * +wqattrs_pod_type(const struct workqueue_attrs *attrs) +{ + struct wq_pod_type *pt = &wq_pod_types[attrs->affn_scope]; + + if (!WARN_ON_ONCE(attrs->affn_scope == WQ_AFFN_NR_TYPES) && + likely(pt->nr_pods)) + return pt; + + /* + * Before workqueue_init_topology(), only SYSTEM is available which is + * initialized in workqueue_init_early(). + */ + pt = &wq_pod_types[WQ_AFFN_SYSTEM]; + BUG_ON(!pt->nr_pods); + return pt; +} + /** * init_worker_pool - initialize a newly zalloc'd worker_pool * @pool: worker_pool to initialize @@ -3924,10 +3952,10 @@ static void put_unbound_pool(struct worker_pool *pool) */ static struct worker_pool *get_unbound_pool(const struct workqueue_attrs *attrs) { + struct wq_pod_type *pt = &wq_pod_types[WQ_AFFN_NUMA]; u32 hash = wqattrs_hash(attrs); struct worker_pool *pool; - int pod; - int target_pod = NUMA_NO_NODE; + int pod, node = NUMA_NO_NODE; lockdep_assert_held(&wq_pool_mutex); @@ -3939,23 +3967,20 @@ static struct worker_pool *get_unbound_pool(const struct workqueue_attrs *attrs) } } - /* if cpumask is contained inside a pod, we belong to that pod */ - if (wq_pod_enabled) { - for_each_node(pod) { - if (cpumask_subset(attrs->cpumask, wq_pod_cpus[pod])) { - target_pod = pod; - break; - } + /* If cpumask is contained inside a NUMA pod, that's our NUMA node */ + for (pod = 0; pod < pt->nr_pods; pod++) { + if (cpumask_subset(attrs->cpumask, pt->pod_cpus[pod])) { + node = pt->pod_node[pod]; + break; } } /* nope, create a new one */ - pool = kzalloc_node(sizeof(*pool), GFP_KERNEL, target_pod); + pool = kzalloc_node(sizeof(*pool), GFP_KERNEL, node); if (!pool || init_worker_pool(pool) < 0) goto fail; - pool->node = target_pod; - + pool->node = node; copy_workqueue_attrs(pool->attrs, attrs); wqattrs_clear_for_pool(pool->attrs); @@ -4143,7 +4168,7 @@ static struct pool_workqueue *alloc_unbound_pwq(struct workqueue_struct *wq, /** * wq_calc_pod_cpumask - calculate a wq_attrs' cpumask for a pod * @attrs: the wq_attrs of the default pwq of the target workqueue - * @pod: the target CPU pod + * @cpu: the target CPU * @cpu_going_down: if >= 0, the CPU to consider as offline * @cpumask: outarg, the resulting cpumask * @@ -4157,30 +4182,29 @@ static struct pool_workqueue *alloc_unbound_pwq(struct workqueue_struct *wq, * * The caller is responsible for ensuring that the cpumask of @pod stays stable. */ -static void wq_calc_pod_cpumask(const struct workqueue_attrs *attrs, int pod, - int cpu_going_down, cpumask_t *cpumask) +static void wq_calc_pod_cpumask(const struct workqueue_attrs *attrs, int cpu, + int cpu_going_down, cpumask_t *cpumask) { - if (!wq_pod_enabled || attrs->ordered) - goto use_dfl; + const struct wq_pod_type *pt = wqattrs_pod_type(attrs); + int pod = pt->cpu_pod[cpu]; /* does @pod have any online CPUs @attrs wants? */ - cpumask_and(cpumask, cpumask_of_node(pod), attrs->cpumask); + cpumask_and(cpumask, pt->pod_cpus[pod], attrs->cpumask); + cpumask_and(cpumask, cpumask, cpu_online_mask); if (cpu_going_down >= 0) cpumask_clear_cpu(cpu_going_down, cpumask); - if (cpumask_empty(cpumask)) - goto use_dfl; + if (cpumask_empty(cpumask)) { + cpumask_copy(cpumask, attrs->cpumask); + return; + } /* yeap, return possible CPUs in @pod that @attrs wants */ - cpumask_and(cpumask, attrs->cpumask, wq_pod_cpus[pod]); + cpumask_and(cpumask, attrs->cpumask, pt->pod_cpus[pod]); if (cpumask_empty(cpumask)) pr_warn_once("WARNING: workqueue cpumask: online intersect > " "possible intersect\n"); - return; - -use_dfl: - cpumask_copy(cpumask, attrs->cpumask); } /* install @pwq into @wq's cpu_pwq and return the old pwq */ @@ -4237,6 +4261,10 @@ apply_wqattrs_prepare(struct workqueue_struct *wq, lockdep_assert_held(&wq_pool_mutex); + if (WARN_ON(attrs->affn_scope < 0 || + attrs->affn_scope >= WQ_AFFN_NR_TYPES)) + return ERR_PTR(-EINVAL); + ctx = kzalloc(struct_size(ctx, pwq_tbl, nr_cpu_ids), GFP_KERNEL); new_attrs = alloc_workqueue_attrs(); @@ -4266,8 +4294,7 @@ apply_wqattrs_prepare(struct workqueue_struct *wq, ctx->dfl_pwq->refcnt++; ctx->pwq_tbl[cpu] = ctx->dfl_pwq; } else { - wq_calc_pod_cpumask(new_attrs, cpu_to_node(cpu), -1, - tmp_attrs->cpumask); + wq_calc_pod_cpumask(new_attrs, cpu, -1, tmp_attrs->cpumask); ctx->pwq_tbl[cpu] = alloc_unbound_pwq(wq, tmp_attrs); if (!ctx->pwq_tbl[cpu]) goto out_free; @@ -4287,7 +4314,7 @@ out_free: free_workqueue_attrs(tmp_attrs); free_workqueue_attrs(new_attrs); apply_wqattrs_cleanup(ctx); - return NULL; + return ERR_PTR(-ENOMEM); } /* set attrs and install prepared pwqs, @ctx points to old pwqs on return */ @@ -4343,8 +4370,8 @@ static int apply_workqueue_attrs_locked(struct workqueue_struct *wq, } ctx = apply_wqattrs_prepare(wq, attrs, wq_unbound_cpumask); - if (!ctx) - return -ENOMEM; + if (IS_ERR(ctx)) + return PTR_ERR(ctx); /* the ctx has been prepared successfully, let's commit it */ apply_wqattrs_commit(ctx); @@ -4409,7 +4436,6 @@ int apply_workqueue_attrs(struct workqueue_struct *wq, static void wq_update_pod(struct workqueue_struct *wq, int cpu, int hotplug_cpu, bool online) { - int pod = cpu_to_node(cpu); int off_cpu = online ? -1 : hotplug_cpu; struct pool_workqueue *old_pwq = NULL, *pwq; struct workqueue_attrs *target_attrs; @@ -4417,8 +4443,7 @@ static void wq_update_pod(struct workqueue_struct *wq, int cpu, lockdep_assert_held(&wq_pool_mutex); - if (!wq_pod_enabled || !(wq->flags & WQ_UNBOUND) || - wq->unbound_attrs->ordered) + if (!(wq->flags & WQ_UNBOUND) || wq->unbound_attrs->ordered) return; /* @@ -4433,7 +4458,7 @@ static void wq_update_pod(struct workqueue_struct *wq, int cpu, wqattrs_actualize_cpumask(target_attrs, wq_unbound_cpumask); /* nothing to do if the target cpumask matches the current pwq */ - wq_calc_pod_cpumask(target_attrs, pod, off_cpu, cpumask); + wq_calc_pod_cpumask(target_attrs, cpu, off_cpu, cpumask); pwq = rcu_dereference_protected(*per_cpu_ptr(wq->cpu_pwq, cpu), lockdep_is_held(&wq_pool_mutex)); if (cpumask_equal(cpumask, pwq->pool->attrs->cpumask)) @@ -5460,12 +5485,14 @@ int workqueue_online_cpu(unsigned int cpu) /* update pod affinity of unbound workqueues */ list_for_each_entry(wq, &workqueues, list) { - int tcpu; + struct workqueue_attrs *attrs = wq->unbound_attrs; + + if (attrs) { + const struct wq_pod_type *pt = wqattrs_pod_type(attrs); + int tcpu; - for_each_possible_cpu(tcpu) { - if (cpu_to_node(tcpu) == cpu_to_node(cpu)) { + for_each_cpu(tcpu, pt->pod_cpus[pt->cpu_pod[cpu]]) wq_update_pod(wq, tcpu, cpu, true); - } } } @@ -5486,12 +5513,14 @@ int workqueue_offline_cpu(unsigned int cpu) /* update pod affinity of unbound workqueues */ mutex_lock(&wq_pool_mutex); list_for_each_entry(wq, &workqueues, list) { - int tcpu; + struct workqueue_attrs *attrs = wq->unbound_attrs; + + if (attrs) { + const struct wq_pod_type *pt = wqattrs_pod_type(attrs); + int tcpu; - for_each_possible_cpu(tcpu) { - if (cpu_to_node(tcpu) == cpu_to_node(cpu)) { + for_each_cpu(tcpu, pt->pod_cpus[pt->cpu_pod[cpu]]) wq_update_pod(wq, tcpu, cpu, false); - } } } mutex_unlock(&wq_pool_mutex); @@ -5689,8 +5718,8 @@ static int workqueue_apply_unbound_cpumask(const cpumask_var_t unbound_cpumask) continue; ctx = apply_wqattrs_prepare(wq, wq->unbound_attrs, unbound_cpumask); - if (!ctx) { - ret = -ENOMEM; + if (IS_ERR(ctx)) { + ret = PTR_ERR(ctx); break; } @@ -6283,6 +6312,7 @@ static inline void wq_watchdog_init(void) { } */ void __init workqueue_init_early(void) { + struct wq_pod_type *pt = &wq_pod_types[WQ_AFFN_SYSTEM]; int std_nice[NR_STD_WORKER_POOLS] = { 0, HIGHPRI_NICE_LEVEL }; int i, cpu; @@ -6302,6 +6332,22 @@ void __init workqueue_init_early(void) BUG_ON(!alloc_cpumask_var(&wq_update_pod_cpumask_buf, GFP_KERNEL)); + /* initialize WQ_AFFN_SYSTEM pods */ + pt->pod_cpus = kcalloc(1, sizeof(pt->pod_cpus[0]), GFP_KERNEL); + pt->pod_node = kcalloc(1, sizeof(pt->pod_node[0]), GFP_KERNEL); + pt->cpu_pod = kcalloc(nr_cpu_ids, sizeof(pt->cpu_pod[0]), GFP_KERNEL); + BUG_ON(!pt->pod_cpus || !pt->pod_node || !pt->cpu_pod); + + BUG_ON(!zalloc_cpumask_var_node(&pt->pod_cpus[0], GFP_KERNEL, NUMA_NO_NODE)); + + wq_update_pod_attrs_buf = alloc_workqueue_attrs(); + BUG_ON(!wq_update_pod_attrs_buf); + + pt->nr_pods = 1; + cpumask_copy(pt->pod_cpus[0], cpu_possible_mask); + pt->pod_node[0] = NUMA_NO_NODE; + pt->cpu_pod[0] = 0; + /* initialize CPU pools */ for_each_possible_cpu(cpu) { struct worker_pool *pool; @@ -6457,8 +6503,8 @@ void __init workqueue_init(void) */ void __init workqueue_init_topology(void) { + struct wq_pod_type *pt = &wq_pod_types[WQ_AFFN_NUMA]; struct workqueue_struct *wq; - cpumask_var_t *tbl; int node, cpu; if (num_possible_nodes() <= 1) @@ -6478,20 +6524,23 @@ void __init workqueue_init_topology(void) * available. Build one from cpu_to_node() which should have been * fully initialized by now. */ - tbl = kcalloc(nr_node_ids, sizeof(tbl[0]), GFP_KERNEL); - BUG_ON(!tbl); + pt->pod_cpus = kcalloc(nr_node_ids, sizeof(pt->pod_cpus[0]), GFP_KERNEL); + pt->pod_node = kcalloc(nr_node_ids, sizeof(pt->pod_node[0]), GFP_KERNEL); + pt->cpu_pod = kcalloc(nr_cpu_ids, sizeof(pt->cpu_pod[0]), GFP_KERNEL); + BUG_ON(!pt->pod_cpus || !pt->pod_node || !pt->cpu_pod); for_each_node(node) - BUG_ON(!zalloc_cpumask_var_node(&tbl[node], GFP_KERNEL, + BUG_ON(!zalloc_cpumask_var_node(&pt->pod_cpus[node], GFP_KERNEL, node_online(node) ? node : NUMA_NO_NODE)); for_each_possible_cpu(cpu) { node = cpu_to_node(cpu); - cpumask_set_cpu(cpu, tbl[node]); + cpumask_set_cpu(cpu, pt->pod_cpus[node]); + pt->pod_node[node] = node; + pt->cpu_pod[cpu] = node; } - wq_pod_cpus = tbl; - wq_pod_enabled = true; + pt->nr_pods = nr_node_ids; /* * Workqueues allocated earlier would have all CPUs sharing the default -- GitLab From 7f7dc377a3b2bbaa8cf8941587c228eab4bd82ec Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:24 -1000 Subject: [PATCH 0892/3445] workqueue: Add tools/workqueue/wq_dump.py which prints out workqueue configuration Lack of visibility has always been a pain point for workqueues. While the recently added wq_monitor.py improved the situation, it's still difficult to understand what worker pools are active in the system, how workqueues map to them and why. The lack of visibility into how workqueues are configured is going to become more noticeable as workqueue improves locality awareness and provides more mechanisms to customize locality related behaviors. Now that the basic framework for more flexible locality support is in place, this is a good time to improve the situation. This patch adds tools/workqueues/wq_dump.py which prints out the topology configuration, worker pools and how workqueues are mapped to pools. Read the command's help message for more details. Signed-off-by: Tejun Heo --- Documentation/core-api/workqueue.rst | 59 ++++++++++ tools/workqueue/wq_dump.py | 166 +++++++++++++++++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 tools/workqueue/wq_dump.py diff --git a/Documentation/core-api/workqueue.rst b/Documentation/core-api/workqueue.rst index 8e541c5d8fa97..c9e46acd339b1 100644 --- a/Documentation/core-api/workqueue.rst +++ b/Documentation/core-api/workqueue.rst @@ -347,6 +347,65 @@ Guidelines level of locality in wq operations and work item execution. +Examining Configuration +======================= + +Use tools/workqueue/wq_dump.py to examine unbound CPU affinity +configuration, worker pools and how workqueues map to the pools: :: + + $ tools/workqueue/wq_dump.py + Affinity Scopes + =============== + wq_unbound_cpumask=0000000f + + NUMA + nr_pods 2 + pod_cpus [0]=00000003 [1]=0000000c + pod_node [0]=0 [1]=1 + cpu_pod [0]=0 [1]=0 [2]=1 [3]=1 + + SYSTEM + nr_pods 1 + pod_cpus [0]=0000000f + pod_node [0]=-1 + cpu_pod [0]=0 [1]=0 [2]=0 [3]=0 + + Worker Pools + ============ + pool[00] ref= 1 nice= 0 idle/workers= 4/ 4 cpu= 0 + pool[01] ref= 1 nice=-20 idle/workers= 2/ 2 cpu= 0 + pool[02] ref= 1 nice= 0 idle/workers= 4/ 4 cpu= 1 + pool[03] ref= 1 nice=-20 idle/workers= 2/ 2 cpu= 1 + pool[04] ref= 1 nice= 0 idle/workers= 4/ 4 cpu= 2 + pool[05] ref= 1 nice=-20 idle/workers= 2/ 2 cpu= 2 + pool[06] ref= 1 nice= 0 idle/workers= 3/ 3 cpu= 3 + pool[07] ref= 1 nice=-20 idle/workers= 2/ 2 cpu= 3 + pool[08] ref=42 nice= 0 idle/workers= 6/ 6 cpus=0000000f + pool[09] ref=28 nice= 0 idle/workers= 3/ 3 cpus=00000003 + pool[10] ref=28 nice= 0 idle/workers= 17/ 17 cpus=0000000c + pool[11] ref= 1 nice=-20 idle/workers= 1/ 1 cpus=0000000f + pool[12] ref= 2 nice=-20 idle/workers= 1/ 1 cpus=00000003 + pool[13] ref= 2 nice=-20 idle/workers= 1/ 1 cpus=0000000c + + Workqueue CPU -> pool + ===================== + [ workqueue \ CPU 0 1 2 3 dfl] + events percpu 0 2 4 6 + events_highpri percpu 1 3 5 7 + events_long percpu 0 2 4 6 + events_unbound unbound 9 9 10 10 8 + events_freezable percpu 0 2 4 6 + events_power_efficient percpu 0 2 4 6 + events_freezable_power_ percpu 0 2 4 6 + rcu_gp percpu 0 2 4 6 + rcu_par_gp percpu 0 2 4 6 + slub_flushwq percpu 0 2 4 6 + netns ordered 8 8 8 8 8 + ... + +See the command's help message for more info. + + Monitoring ========== diff --git a/tools/workqueue/wq_dump.py b/tools/workqueue/wq_dump.py new file mode 100644 index 0000000000000..ddd0bb4395ea8 --- /dev/null +++ b/tools/workqueue/wq_dump.py @@ -0,0 +1,166 @@ +#!/usr/bin/env drgn +# +# Copyright (C) 2023 Tejun Heo +# Copyright (C) 2023 Meta Platforms, Inc. and affiliates. + +desc = """ +This is a drgn script to show the current workqueue configuration. For more +info on drgn, visit https://github.com/osandov/drgn. + +Affinity Scopes +=============== + +Shows the CPUs that can be used for unbound workqueues and how they will be +grouped by each available affinity type. For each type: + + nr_pods number of CPU pods in the affinity type + pod_cpus CPUs in each pod + pod_node NUMA node for memory allocation for each pod + cpu_pod pod that each CPU is associated to + +Worker Pools +============ + +Lists all worker pools indexed by their ID. For each pool: + + ref number of pool_workqueue's associated with this pool + nice nice value of the worker threads in the pool + idle number of idle workers + workers number of all workers + cpu CPU the pool is associated with (per-cpu pool) + cpus CPUs the workers in the pool can run on (unbound pool) + +Workqueue CPU -> pool +===================== + +Lists all workqueues along with their type and worker pool association. For +each workqueue: + + NAME TYPE POOL_ID... + + NAME name of the workqueue + TYPE percpu, unbound or ordered + POOL_ID worker pool ID associated with each possible CPU +""" + +import sys + +import drgn +from drgn.helpers.linux.list import list_for_each_entry,list_empty +from drgn.helpers.linux.percpu import per_cpu_ptr +from drgn.helpers.linux.cpumask import for_each_cpu,for_each_possible_cpu +from drgn.helpers.linux.idr import idr_for_each + +import argparse +parser = argparse.ArgumentParser(description=desc, + formatter_class=argparse.RawTextHelpFormatter) +args = parser.parse_args() + +def err(s): + print(s, file=sys.stderr, flush=True) + sys.exit(1) + +def cpumask_str(cpumask): + output = "" + base = 0 + v = 0 + for cpu in for_each_cpu(cpumask[0]): + while cpu - base >= 32: + output += f'{hex(v)} ' + base += 32 + v = 0 + v |= 1 << (cpu - base) + if v > 0: + output += f'{v:08x}' + return output.strip() + +worker_pool_idr = prog['worker_pool_idr'] +workqueues = prog['workqueues'] +wq_unbound_cpumask = prog['wq_unbound_cpumask'] +wq_pod_types = prog['wq_pod_types'] + +WQ_UNBOUND = prog['WQ_UNBOUND'] +WQ_ORDERED = prog['__WQ_ORDERED'] +WQ_MEM_RECLAIM = prog['WQ_MEM_RECLAIM'] + +WQ_AFFN_NUMA = prog['WQ_AFFN_NUMA'] +WQ_AFFN_SYSTEM = prog['WQ_AFFN_SYSTEM'] + +print('Affinity Scopes') +print('===============') + +print(f'wq_unbound_cpumask={cpumask_str(wq_unbound_cpumask)}') + +def print_pod_type(pt): + print(f' nr_pods {pt.nr_pods.value_()}') + + print(' pod_cpus', end='') + for pod in range(pt.nr_pods): + print(f' [{pod}]={cpumask_str(pt.pod_cpus[pod])}', end='') + print('') + + print(' pod_node', end='') + for pod in range(pt.nr_pods): + print(f' [{pod}]={pt.pod_node[pod].value_()}', end='') + print('') + + print(f' cpu_pod ', end='') + for cpu in for_each_possible_cpu(prog): + print(f' [{cpu}]={pt.cpu_pod[cpu].value_()}', end='') + print('') + +print('') +print('NUMA') +print_pod_type(wq_pod_types[WQ_AFFN_NUMA]) +print('') +print('SYSTEM') +print_pod_type(wq_pod_types[WQ_AFFN_SYSTEM]) + +print('') +print('Worker Pools') +print('============') + +max_pool_id_len = 0 +max_ref_len = 0 +for pi, pool in idr_for_each(worker_pool_idr): + pool = drgn.Object(prog, 'struct worker_pool', address=pool) + max_pool_id_len = max(max_pool_id_len, len(f'{pi}')) + max_ref_len = max(max_ref_len, len(f'{pool.refcnt.value_()}')) + +for pi, pool in idr_for_each(worker_pool_idr): + pool = drgn.Object(prog, 'struct worker_pool', address=pool) + print(f'pool[{pi:0{max_pool_id_len}}] ref={pool.refcnt.value_():{max_ref_len}} nice={pool.attrs.nice.value_():3} ', end='') + print(f'idle/workers={pool.nr_idle.value_():3}/{pool.nr_workers.value_():3} ', end='') + if pool.cpu >= 0: + print(f'cpu={pool.cpu.value_():3}', end='') + else: + print(f'cpus={cpumask_str(pool.attrs.cpumask)}', end='') + print('') + +print('') +print('Workqueue CPU -> pool') +print('=====================') + +print('[ workqueue \ CPU ', end='') +for cpu in for_each_possible_cpu(prog): + print(f' {cpu:{max_pool_id_len}}', end='') +print(' dfl]') + +for wq in list_for_each_entry('struct workqueue_struct', workqueues.address_of_(), 'list'): + print(f'{wq.name.string_().decode()[-24:]:24}', end='') + if wq.flags & WQ_UNBOUND: + if wq.flags & WQ_ORDERED: + print(' ordered', end='') + else: + print(' unbound', end='') + else: + print(' percpu ', end='') + + for cpu in for_each_possible_cpu(prog): + pool_id = per_cpu_ptr(wq.cpu_pwq, cpu)[0].pool.id.value_() + field_len = max(len(str(cpu)), max_pool_id_len) + print(f' {pool_id:{field_len}}', end='') + + if wq.flags & WQ_UNBOUND: + print(f' {wq.dfl_pwq.pool.id.value_():{max_pool_id_len}}', end='') + print('') -- GitLab From 025e16845877e80cb169274b330c236056ba553c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:24 -1000 Subject: [PATCH 0893/3445] workqueue: Modularize wq_pod_type initialization While wq_pod_type[] can now group CPUs in any aribitrary way, WQ_AFFN_NUM init is hard coded into workqueue_init_topology(). This patch modularizes the init path by introducing init_pod_type() which takes a callback to determine whether two CPUs should share a pod as an argument. init_pod_type() first scans the CPU combinations testing for sharing to assign consecutive pod IDs and initialize pod_type->cpu_pod[]. Once ->cpu_pod[] is determined, ->pod_cpus[] and ->pod_node[] are initialized accordingly. WQ_AFFN_NUMA is now initialized by calling init_pod_type() with cpus_share_numa() which tests whether the CPU belongs to the same NUMA node. This patch may change the pod ID assigned to each NUMA node but that shouldn't cause any behavior changes as the NUMA node to use for allocations are tracked separately in pod_type->pod_node[]. This makes adding new affinty types pretty easy. Signed-off-by: Tejun Heo --- kernel/workqueue.c | 84 +++++++++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 34 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 6c4d7b1fdf9a1..a2cc0432abd5e 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -6494,6 +6494,54 @@ void __init workqueue_init(void) wq_watchdog_init(); } +/* + * Initialize @pt by first initializing @pt->cpu_pod[] with pod IDs according to + * @cpu_shares_pod(). Each subset of CPUs that share a pod is assigned a unique + * and consecutive pod ID. The rest of @pt is initialized accordingly. + */ +static void __init init_pod_type(struct wq_pod_type *pt, + bool (*cpus_share_pod)(int, int)) +{ + int cur, pre, cpu, pod; + + pt->nr_pods = 0; + + /* init @pt->cpu_pod[] according to @cpus_share_pod() */ + pt->cpu_pod = kcalloc(nr_cpu_ids, sizeof(pt->cpu_pod[0]), GFP_KERNEL); + BUG_ON(!pt->cpu_pod); + + for_each_possible_cpu(cur) { + for_each_possible_cpu(pre) { + if (pre >= cur) { + pt->cpu_pod[cur] = pt->nr_pods++; + break; + } + if (cpus_share_pod(cur, pre)) { + pt->cpu_pod[cur] = pt->cpu_pod[pre]; + break; + } + } + } + + /* init the rest to match @pt->cpu_pod[] */ + pt->pod_cpus = kcalloc(pt->nr_pods, sizeof(pt->pod_cpus[0]), GFP_KERNEL); + pt->pod_node = kcalloc(pt->nr_pods, sizeof(pt->pod_node[0]), GFP_KERNEL); + BUG_ON(!pt->pod_cpus || !pt->pod_node); + + for (pod = 0; pod < pt->nr_pods; pod++) + BUG_ON(!zalloc_cpumask_var(&pt->pod_cpus[pod], GFP_KERNEL)); + + for_each_possible_cpu(cpu) { + cpumask_set_cpu(cpu, pt->pod_cpus[pt->cpu_pod[cpu]]); + pt->pod_node[pt->cpu_pod[cpu]] = cpu_to_node(cpu); + } +} + +static bool __init cpus_share_numa(int cpu0, int cpu1) +{ + return cpu_to_node(cpu0) == cpu_to_node(cpu1); +} + /** * workqueue_init_topology - initialize CPU pods for unbound workqueues * @@ -6503,45 +6551,13 @@ void __init workqueue_init(void) */ void __init workqueue_init_topology(void) { - struct wq_pod_type *pt = &wq_pod_types[WQ_AFFN_NUMA]; struct workqueue_struct *wq; - int node, cpu; - - if (num_possible_nodes() <= 1) - return; + int cpu; - for_each_possible_cpu(cpu) { - if (WARN_ON(cpu_to_node(cpu) == NUMA_NO_NODE)) { - pr_warn("workqueue: NUMA node mapping not available for cpu%d, disabling NUMA support\n", cpu); - return; - } - } + init_pod_type(&wq_pod_types[WQ_AFFN_NUMA], cpus_share_numa); mutex_lock(&wq_pool_mutex); - /* - * We want masks of possible CPUs of each node which isn't readily - * available. Build one from cpu_to_node() which should have been - * fully initialized by now. - */ - pt->pod_cpus = kcalloc(nr_node_ids, sizeof(pt->pod_cpus[0]), GFP_KERNEL); - pt->pod_node = kcalloc(nr_node_ids, sizeof(pt->pod_node[0]), GFP_KERNEL); - pt->cpu_pod = kcalloc(nr_cpu_ids, sizeof(pt->cpu_pod[0]), GFP_KERNEL); - BUG_ON(!pt->pod_cpus || !pt->pod_node || !pt->cpu_pod); - - for_each_node(node) - BUG_ON(!zalloc_cpumask_var_node(&pt->pod_cpus[node], GFP_KERNEL, - node_online(node) ? node : NUMA_NO_NODE)); - - for_each_possible_cpu(cpu) { - node = cpu_to_node(cpu); - cpumask_set_cpu(cpu, pt->pod_cpus[node]); - pt->pod_node[node] = node; - pt->cpu_pod[cpu] = node; - } - - pt->nr_pods = nr_node_ids; - /* * Workqueues allocated earlier would have all CPUs sharing the default * worker pool. Explicitly call wq_update_pod() on all workqueue and CPU -- GitLab From 63c5484e74952f60f5810256bd69814d167b8d22 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:24 -1000 Subject: [PATCH 0894/3445] workqueue: Add multiple affinity scopes and interface to select them Add three more affinity scopes - WQ_AFFN_CPU, SMT and CACHE - and make CACHE the default. The code changes to actually add the additional scopes are trivial. Also add module parameter "workqueue.default_affinity_scope" to override the default scope and "affinity_scope" sysfs file to configure it per workqueue. wq_dump.py and documentations are updated accordingly. This enables significant flexibility in configuring how unbound workqueues behave. If affinity scope is set to "cpu", it'll behave close to a per-cpu workqueue. On the other hand, "system" removes all locality boundaries. Many modern machines have multiple L3 caches often while being mostly uniform in terms of memory access. Thus, workqueue's previous behavior of spreading work items in each NUMA node had negative performance implications from unncessarily crossing L3 boundaries between issue and execution. However, picking a finer grained affinity scope also has a downside in that an issuer in one group can't utilize CPUs in other groups. While dependent on the specifics of workload, there's usually a noticeable penalty in crossing L3 boundaries, so let's default to CACHE. This issue will be further addressed and documented with examples in future patches. Signed-off-by: Tejun Heo --- .../admin-guide/kernel-parameters.txt | 12 ++ Documentation/core-api/workqueue.rst | 63 ++++++++++ include/linux/workqueue.h | 5 +- kernel/workqueue.c | 110 +++++++++++++++++- tools/workqueue/wq_dump.py | 15 ++- 5 files changed, 193 insertions(+), 12 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 2b89cbc39713a..732c5c7e3fa54 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -7007,6 +7007,18 @@ The default value of this parameter is determined by the config option CONFIG_WQ_POWER_EFFICIENT_DEFAULT. + workqueue.default_affinity_scope= + Select the default affinity scope to use for unbound + workqueues. Can be one of "cpu", "smt", "cache", + "numa" and "system". Default is "cache". For more + information, see the Affinity Scopes section in + Documentation/core-api/workqueue.rst. + + This can be updated after boot through the matching + file under /sys/module/workqueue/parameters. + However, the changed default will only apply to + unbound workqueues created afterwards. + workqueue.debug_force_rr_cpu Workqueue used to implicitly guarantee that work items queued without explicit CPU specified are put diff --git a/Documentation/core-api/workqueue.rst b/Documentation/core-api/workqueue.rst index c9e46acd339b1..56af317508c9c 100644 --- a/Documentation/core-api/workqueue.rst +++ b/Documentation/core-api/workqueue.rst @@ -347,6 +347,51 @@ Guidelines level of locality in wq operations and work item execution. +Affinity Scopes +=============== + +An unbound workqueue groups CPUs according to its affinity scope to improve +cache locality. For example, if a workqueue is using the default affinity +scope of "cache", it will group CPUs according to last level cache +boundaries. A work item queued on the workqueue will be processed by a +worker running on one of the CPUs which share the last level cache with the +issuing CPU. + +Workqueue currently supports the following five affinity scopes. + +``cpu`` + CPUs are not grouped. A work item issued on one CPU is processed by a + worker on the same CPU. This makes unbound workqueues behave as per-cpu + workqueues without concurrency management. + +``smt`` + CPUs are grouped according to SMT boundaries. This usually means that the + logical threads of each physical CPU core are grouped together. + +``cache`` + CPUs are grouped according to cache boundaries. Which specific cache + boundary is used is determined by the arch code. L3 is used in a lot of + cases. This is the default affinity scope. + +``numa`` + CPUs are grouped according to NUMA bounaries. + +``system`` + All CPUs are put in the same group. Workqueue makes no effort to process a + work item on a CPU close to the issuing CPU. + +The default affinity scope can be changed with the module parameter +``workqueue.default_affinity_scope`` and a specific workqueue's affinity +scope can be changed using ``apply_workqueue_attrs()``. + +If ``WQ_SYSFS`` is set, the workqueue will have the following affinity scope +related interface files under its ``/sys/devices/virtual/WQ_NAME/`` +directory. + +``affinity_scope`` + Read to see the current affinity scope. Write to change. + + Examining Configuration ======================= @@ -358,6 +403,24 @@ configuration, worker pools and how workqueues map to the pools: :: =============== wq_unbound_cpumask=0000000f + CPU + nr_pods 4 + pod_cpus [0]=00000001 [1]=00000002 [2]=00000004 [3]=00000008 + pod_node [0]=0 [1]=0 [2]=1 [3]=1 + cpu_pod [0]=0 [1]=1 [2]=2 [3]=3 + + SMT + nr_pods 4 + pod_cpus [0]=00000001 [1]=00000002 [2]=00000004 [3]=00000008 + pod_node [0]=0 [1]=0 [2]=1 [3]=1 + cpu_pod [0]=0 [1]=1 [2]=2 [3]=3 + + CACHE (default) + nr_pods 2 + pod_cpus [0]=00000003 [1]=0000000c + pod_node [0]=0 [1]=1 + cpu_pod [0]=0 [1]=0 [2]=1 [3]=1 + NUMA nr_pods 2 pod_cpus [0]=00000003 [1]=0000000c diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 180491ee6706b..568cfbc24bc0f 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -126,12 +126,15 @@ struct rcu_work { }; enum wq_affn_scope { + WQ_AFFN_CPU, /* one pod per CPU */ + WQ_AFFN_SMT, /* one pod poer SMT */ + WQ_AFFN_CACHE, /* one pod per LLC */ WQ_AFFN_NUMA, /* one pod per NUMA node */ WQ_AFFN_SYSTEM, /* one pod across the whole system */ WQ_AFFN_NR_TYPES, - WQ_AFFN_DFL = WQ_AFFN_NUMA, + WQ_AFFN_DFL = WQ_AFFN_CACHE, }; /** diff --git a/kernel/workqueue.c b/kernel/workqueue.c index a2cc0432abd5e..8e3a499c3f00d 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -338,6 +338,15 @@ struct wq_pod_type { }; static struct wq_pod_type wq_pod_types[WQ_AFFN_NR_TYPES]; +static enum wq_affn_scope wq_affn_dfl = WQ_AFFN_DFL; + +static const char *wq_affn_names[WQ_AFFN_NR_TYPES] = { + [WQ_AFFN_CPU] = "cpu", + [WQ_AFFN_SMT] = "smt", + [WQ_AFFN_CACHE] = "cache", + [WQ_AFFN_NUMA] = "numa", + [WQ_AFFN_SYSTEM] = "system", +}; /* * Per-cpu work items which run for longer than the following threshold are @@ -3664,7 +3673,7 @@ struct workqueue_attrs *alloc_workqueue_attrs(void) goto fail; cpumask_copy(attrs->cpumask, cpu_possible_mask); - attrs->affn_scope = WQ_AFFN_DFL; + attrs->affn_scope = wq_affn_dfl; return attrs; fail: free_workqueue_attrs(attrs); @@ -5777,19 +5786,55 @@ out_unlock: return ret; } +static int parse_affn_scope(const char *val) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(wq_affn_names); i++) { + if (!strncasecmp(val, wq_affn_names[i], strlen(wq_affn_names[i]))) + return i; + } + return -EINVAL; +} + +static int wq_affn_dfl_set(const char *val, const struct kernel_param *kp) +{ + int affn; + + affn = parse_affn_scope(val); + if (affn < 0) + return affn; + + wq_affn_dfl = affn; + return 0; +} + +static int wq_affn_dfl_get(char *buffer, const struct kernel_param *kp) +{ + return scnprintf(buffer, PAGE_SIZE, "%s\n", wq_affn_names[wq_affn_dfl]); +} + +static const struct kernel_param_ops wq_affn_dfl_ops = { + .set = wq_affn_dfl_set, + .get = wq_affn_dfl_get, +}; + +module_param_cb(default_affinity_scope, &wq_affn_dfl_ops, NULL, 0644); + #ifdef CONFIG_SYSFS /* * Workqueues with WQ_SYSFS flag set is visible to userland via * /sys/bus/workqueue/devices/WQ_NAME. All visible workqueues have the * following attributes. * - * per_cpu RO bool : whether the workqueue is per-cpu or unbound - * max_active RW int : maximum number of in-flight work items + * per_cpu RO bool : whether the workqueue is per-cpu or unbound + * max_active RW int : maximum number of in-flight work items * * Unbound workqueues have the following extra attributes. * - * nice RW int : nice value of the workers - * cpumask RW mask : bitmask of allowed CPUs for the workers + * nice RW int : nice value of the workers + * cpumask RW mask : bitmask of allowed CPUs for the workers + * affinity_scope RW str : worker CPU affinity scope (cache, numa, none) */ struct wq_device { struct workqueue_struct *wq; @@ -5932,9 +5977,47 @@ out_unlock: return ret ?: count; } +static ssize_t wq_affn_scope_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct workqueue_struct *wq = dev_to_wq(dev); + int written; + + mutex_lock(&wq->mutex); + written = scnprintf(buf, PAGE_SIZE, "%s\n", + wq_affn_names[wq->unbound_attrs->affn_scope]); + mutex_unlock(&wq->mutex); + + return written; +} + +static ssize_t wq_affn_scope_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct workqueue_struct *wq = dev_to_wq(dev); + struct workqueue_attrs *attrs; + int affn, ret = -ENOMEM; + + affn = parse_affn_scope(buf); + if (affn < 0) + return affn; + + apply_wqattrs_lock(); + attrs = wq_sysfs_prep_attrs(wq); + if (attrs) { + attrs->affn_scope = affn; + ret = apply_workqueue_attrs_locked(wq, attrs); + } + apply_wqattrs_unlock(); + free_workqueue_attrs(attrs); + return ret ?: count; +} + static struct device_attribute wq_sysfs_unbound_attrs[] = { __ATTR(nice, 0644, wq_nice_show, wq_nice_store), __ATTR(cpumask, 0644, wq_cpumask_show, wq_cpumask_store), + __ATTR(affinity_scope, 0644, wq_affn_scope_show, wq_affn_scope_store), __ATTR_NULL, }; @@ -6537,6 +6620,20 @@ static void __init init_pod_type(struct wq_pod_type *pt, } } +static bool __init cpus_dont_share(int cpu0, int cpu1) +{ + return false; +} + +static bool __init cpus_share_smt(int cpu0, int cpu1) +{ +#ifdef CONFIG_SCHED_SMT + return cpumask_test_cpu(cpu0, cpu_smt_mask(cpu1)); +#else + return false; +#endif +} + static bool __init cpus_share_numa(int cpu0, int cpu1) { return cpu_to_node(cpu0) == cpu_to_node(cpu1); @@ -6554,6 +6651,9 @@ void __init workqueue_init_topology(void) struct workqueue_struct *wq; int cpu; + init_pod_type(&wq_pod_types[WQ_AFFN_CPU], cpus_dont_share); + init_pod_type(&wq_pod_types[WQ_AFFN_SMT], cpus_share_smt); + init_pod_type(&wq_pod_types[WQ_AFFN_CACHE], cpus_share_cache); init_pod_type(&wq_pod_types[WQ_AFFN_NUMA], cpus_share_numa); mutex_lock(&wq_pool_mutex); diff --git a/tools/workqueue/wq_dump.py b/tools/workqueue/wq_dump.py index ddd0bb4395ea8..43ab71a193b83 100644 --- a/tools/workqueue/wq_dump.py +++ b/tools/workqueue/wq_dump.py @@ -78,11 +78,16 @@ worker_pool_idr = prog['worker_pool_idr'] workqueues = prog['workqueues'] wq_unbound_cpumask = prog['wq_unbound_cpumask'] wq_pod_types = prog['wq_pod_types'] +wq_affn_dfl = prog['wq_affn_dfl'] +wq_affn_names = prog['wq_affn_names'] WQ_UNBOUND = prog['WQ_UNBOUND'] WQ_ORDERED = prog['__WQ_ORDERED'] WQ_MEM_RECLAIM = prog['WQ_MEM_RECLAIM'] +WQ_AFFN_CPU = prog['WQ_AFFN_CPU'] +WQ_AFFN_SMT = prog['WQ_AFFN_SMT'] +WQ_AFFN_CACHE = prog['WQ_AFFN_CACHE'] WQ_AFFN_NUMA = prog['WQ_AFFN_NUMA'] WQ_AFFN_SYSTEM = prog['WQ_AFFN_SYSTEM'] @@ -109,12 +114,10 @@ def print_pod_type(pt): print(f' [{cpu}]={pt.cpu_pod[cpu].value_()}', end='') print('') -print('') -print('NUMA') -print_pod_type(wq_pod_types[WQ_AFFN_NUMA]) -print('') -print('SYSTEM') -print_pod_type(wq_pod_types[WQ_AFFN_SYSTEM]) +for affn in [WQ_AFFN_CPU, WQ_AFFN_SMT, WQ_AFFN_CACHE, WQ_AFFN_NUMA, WQ_AFFN_SYSTEM]: + print('') + print(f'{wq_affn_names[affn].string_().decode().upper()}{" (default)" if affn == wq_affn_dfl else ""}') + print_pod_type(wq_pod_types[affn]) print('') print('Worker Pools') -- GitLab From 873eaca6eaf84b1d1ed5b7259308c6a4fca70fdc Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:25 -1000 Subject: [PATCH 0895/3445] workqueue: Factor out work to worker assignment and collision handling The two work execution paths in worker_thread() and rescuer_thread() use move_linked_works() to claim work items from @pool->worklist. Once claimed, process_schedule_works() is called which invokes process_one_work() on each work item. process_one_work() then uses find_worker_executing_work() to detect and handle collisions - situations where the work item to be executed is still running on another worker. This works fine, but, to improve work execution locality, we want to establish work to worker association earlier and know for sure that the worker is going to excute the work once asssigned, which requires performing collision handling earlier while trying to assign the work item to the worker. This patch introduces assign_work() which assigns a work item to a worker using move_linked_works() and then performs collision handling. As collision handling is handled earlier, process_one_work() no longer needs to worry about them. After the this patch, collision checks for linked work items are skipped, which should be fine as they can't be queued multiple times concurrently. For work items running from rescuers, the timing of collision handling may change but the invariant that the work items go through collision handling before starting execution does not. This patch shouldn't cause noticeable behavior changes, especially given that worker_thread() behavior remains the same. Signed-off-by: Tejun Heo --- kernel/workqueue.c | 80 ++++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 28 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 8e3a499c3f00d..8d04169819473 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1025,13 +1025,10 @@ static struct worker *find_worker_executing_work(struct worker_pool *pool, * @head: target list to append @work to * @nextp: out parameter for nested worklist walking * - * Schedule linked works starting from @work to @head. Work series to - * be scheduled starts at @work and includes any consecutive work with - * WORK_STRUCT_LINKED set in its predecessor. - * - * If @nextp is not NULL, it's updated to point to the next work of - * the last scheduled work. This allows move_linked_works() to be - * nested inside outer list_for_each_entry_safe(). + * Schedule linked works starting from @work to @head. Work series to be + * scheduled starts at @work and includes any consecutive work with + * WORK_STRUCT_LINKED set in its predecessor. See assign_work() for details on + * @nextp. * * CONTEXT: * raw_spin_lock_irq(pool->lock). @@ -1060,6 +1057,48 @@ static void move_linked_works(struct work_struct *work, struct list_head *head, *nextp = n; } +/** + * assign_work - assign a work item and its linked work items to a worker + * @work: work to assign + * @worker: worker to assign to + * @nextp: out parameter for nested worklist walking + * + * Assign @work and its linked work items to @worker. If @work is already being + * executed by another worker in the same pool, it'll be punted there. + * + * If @nextp is not NULL, it's updated to point to the next work of the last + * scheduled work. This allows assign_work() to be nested inside + * list_for_each_entry_safe(). + * + * Returns %true if @work was successfully assigned to @worker. %false if @work + * was punted to another worker already executing it. + */ +static bool assign_work(struct work_struct *work, struct worker *worker, + struct work_struct **nextp) +{ + struct worker_pool *pool = worker->pool; + struct worker *collision; + + lockdep_assert_held(&pool->lock); + + /* + * A single work shouldn't be executed concurrently by multiple workers. + * __queue_work() ensures that @work doesn't jump to a different pool + * while still running in the previous pool. Here, we should ensure that + * @work is not executed concurrently by multiple workers from the same + * pool. Check whether anyone is already processing the work. If so, + * defer the work to the currently executing one. + */ + collision = find_worker_executing_work(pool, work); + if (unlikely(collision)) { + move_linked_works(work, &collision->scheduled, nextp); + return false; + } + + move_linked_works(work, &worker->scheduled, nextp); + return true; +} + /** * wake_up_worker - wake up an idle worker * @pool: worker pool to wake worker from @@ -2462,7 +2501,6 @@ __acquires(&pool->lock) struct pool_workqueue *pwq = get_work_pwq(work); struct worker_pool *pool = worker->pool; unsigned long work_data; - struct worker *collision; #ifdef CONFIG_LOCKDEP /* * It is permissible to free the struct work_struct from @@ -2479,18 +2517,6 @@ __acquires(&pool->lock) WARN_ON_ONCE(!(pool->flags & POOL_DISASSOCIATED) && raw_smp_processor_id() != pool->cpu); - /* - * A single work shouldn't be executed concurrently by - * multiple workers on a single cpu. Check whether anyone is - * already processing the work. If so, defer the work to the - * currently executing one. - */ - collision = find_worker_executing_work(pool, work); - if (unlikely(collision)) { - move_linked_works(work, &collision->scheduled, NULL); - return; - } - /* claim and dequeue */ debug_work_deactivate(work); hash_add(pool->busy_hash, &worker->hentry, (unsigned long)work); @@ -2717,8 +2743,8 @@ recheck: list_first_entry(&pool->worklist, struct work_struct, entry); - move_linked_works(work, &worker->scheduled, NULL); - process_scheduled_works(worker); + if (assign_work(work, worker, NULL)) + process_scheduled_works(worker); } while (keep_working(pool)); worker_set_flags(worker, WORKER_PREP); @@ -2762,7 +2788,6 @@ static int rescuer_thread(void *__rescuer) { struct worker *rescuer = __rescuer; struct workqueue_struct *wq = rescuer->rescue_wq; - struct list_head *scheduled = &rescuer->scheduled; bool should_stop; set_user_nice(current, RESCUER_NICE_LEVEL); @@ -2807,15 +2832,14 @@ repeat: * Slurp in all works issued via this workqueue and * process'em. */ - WARN_ON_ONCE(!list_empty(scheduled)); + WARN_ON_ONCE(!list_empty(&rescuer->scheduled)); list_for_each_entry_safe(work, n, &pool->worklist, entry) { - if (get_work_pwq(work) == pwq) { - move_linked_works(work, scheduled, &n); + if (get_work_pwq(work) == pwq && + assign_work(work, rescuer, &n)) pwq->stats[PWQ_STAT_RESCUED]++; - } } - if (!list_empty(scheduled)) { + if (!list_empty(&rescuer->scheduled)) { process_scheduled_works(rescuer); /* -- GitLab From 0219a3528d72143d8d2c4c793b61541d03518b59 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:25 -1000 Subject: [PATCH 0896/3445] workqueue: Factor out need_more_worker() check and worker wake-up Checking need_more_worker() and calling wake_up_worker() is a repeated pattern. Let's add kick_pool(), which checks need_more_worker() and open-code wake_up_worker(), and replace wake_up_worker() uses. The following conversions aren't one-to-one: * __queue_work() was using __need_more_work() because it knows that pool->worklist isn't empty. Switching to kick_pool() adds an extra list_empty() test. * create_worker() always needs to wake up the newly minted worker whether there's more work to do or not to avoid triggering hung task check on the new task. Keep the current wake_up_process() and still add kick_pool(). This may lead to an extra wakeup which isn't harmful. * pwq_adjust_max_active() was explicitly checking whether it needs to wake up a worker or not to avoid spurious wakeups. As kick_pool() only wakes up a worker when necessary, this explicit check is no longer necessary and dropped. * unbind_workers() now calls kick_pool() instead of wake_up_worker() adding a need_more_worker() test. This avoids spurious wakeups and shouldn't break anything. wake_up_worker() is dropped as kick_pool() replaces all its users. After this patch, all paths that wakes up a non-rescuer worker to initiate work item execution use kick_pool(). This will enable future changes to improve locality. Signed-off-by: Tejun Heo --- kernel/workqueue.c | 87 ++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 50 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 8d04169819473..e941fa052a2bf 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -815,11 +815,6 @@ static bool work_is_canceling(struct work_struct *work) * they're being called with pool->lock held. */ -static bool __need_more_worker(struct worker_pool *pool) -{ - return !pool->nr_running; -} - /* * Need to wake up a worker? Called from anything but currently * running workers. @@ -830,7 +825,7 @@ static bool __need_more_worker(struct worker_pool *pool) */ static bool need_more_worker(struct worker_pool *pool) { - return !list_empty(&pool->worklist) && __need_more_worker(pool); + return !list_empty(&pool->worklist) && !pool->nr_running; } /* Can I start working? Called from busy but !running workers. */ @@ -1100,20 +1095,23 @@ static bool assign_work(struct work_struct *work, struct worker *worker, } /** - * wake_up_worker - wake up an idle worker - * @pool: worker pool to wake worker from - * - * Wake up the first idle worker of @pool. + * kick_pool - wake up an idle worker if necessary + * @pool: pool to kick * - * CONTEXT: - * raw_spin_lock_irq(pool->lock). + * @pool may have pending work items. Wake up worker if necessary. Returns + * whether a worker was woken up. */ -static void wake_up_worker(struct worker_pool *pool) +static bool kick_pool(struct worker_pool *pool) { struct worker *worker = first_idle_worker(pool); - if (likely(worker)) - wake_up_process(worker->task); + lockdep_assert_held(&pool->lock); + + if (!need_more_worker(pool) || !worker) + return false; + + wake_up_process(worker->task); + return true; } #ifdef CONFIG_WQ_CPU_INTENSIVE_REPORT @@ -1281,10 +1279,9 @@ void wq_worker_sleeping(struct task_struct *task) } pool->nr_running--; - if (need_more_worker(pool)) { + if (kick_pool(pool)) worker->current_pwq->stats[PWQ_STAT_CM_WAKEUP]++; - wake_up_worker(pool); - } + raw_spin_unlock_irq(&pool->lock); } @@ -1332,10 +1329,8 @@ void wq_worker_tick(struct task_struct *task) wq_cpu_intensive_report(worker->current_func); pwq->stats[PWQ_STAT_CPU_INTENSIVE]++; - if (need_more_worker(pool)) { + if (kick_pool(pool)) pwq->stats[PWQ_STAT_CM_WAKEUP]++; - wake_up_worker(pool); - } raw_spin_unlock(&pool->lock); } @@ -1773,9 +1768,7 @@ retry: trace_workqueue_activate_work(work); pwq->nr_active++; insert_work(pwq, work, &pool->worklist, work_flags); - - if (__need_more_worker(pool)) - wake_up_worker(pool); + kick_pool(pool); } else { work_flags |= WORK_STRUCT_INACTIVE; insert_work(pwq, work, &pwq->inactive_works, work_flags); @@ -2181,9 +2174,18 @@ static struct worker *create_worker(struct worker_pool *pool) /* start the newly created worker */ raw_spin_lock_irq(&pool->lock); + worker->pool->nr_workers++; worker_enter_idle(worker); + kick_pool(pool); + + /* + * @worker is waiting on a completion in kthread() and will trigger hung + * check if not woken up soon. As kick_pool() might not have waken it + * up, wake it up explicitly once more. + */ wake_up_process(worker->task); + raw_spin_unlock_irq(&pool->lock); return worker; @@ -2545,14 +2547,12 @@ __acquires(&pool->lock) worker_set_flags(worker, WORKER_CPU_INTENSIVE); /* - * Wake up another worker if necessary. The condition is always - * false for normal per-cpu workers since nr_running would always - * be >= 1 at this point. This is used to chain execution of the - * pending work items for WORKER_NOT_RUNNING workers such as the - * UNBOUND and CPU_INTENSIVE ones. + * Kick @pool if necessary. It's always noop for per-cpu worker pools + * since nr_running would always be >= 1 at this point. This is used to + * chain execution of the pending work items for WORKER_NOT_RUNNING + * workers such as the UNBOUND and CPU_INTENSIVE ones. */ - if (need_more_worker(pool)) - wake_up_worker(pool); + kick_pool(pool); /* * Record the last pool and clear PENDING which should be the last @@ -2872,12 +2872,10 @@ repeat: put_pwq(pwq); /* - * Leave this pool. If need_more_worker() is %true, notify a - * regular worker; otherwise, we end up with 0 concurrency - * and stalling the execution. + * Leave this pool. Notify regular workers; otherwise, we end up + * with 0 concurrency and stalling the execution. */ - if (need_more_worker(pool)) - wake_up_worker(pool); + kick_pool(pool); raw_spin_unlock_irq(&pool->lock); @@ -4111,24 +4109,13 @@ static void pwq_adjust_max_active(struct pool_workqueue *pwq) * is updated and visible. */ if (!freezable || !workqueue_freezing) { - bool kick = false; - pwq->max_active = wq->saved_max_active; while (!list_empty(&pwq->inactive_works) && - pwq->nr_active < pwq->max_active) { + pwq->nr_active < pwq->max_active) pwq_activate_first_inactive(pwq); - kick = true; - } - /* - * Need to kick a worker after thawed or an unbound wq's - * max_active is bumped. In realtime scenarios, always kicking a - * worker will cause interference on the isolated cpu cores, so - * let's kick iff work items were activated. - */ - if (kick) - wake_up_worker(pwq->pool); + kick_pool(pwq->pool); } else { pwq->max_active = 0; } @@ -5389,7 +5376,7 @@ static void unbind_workers(int cpu) * worker blocking could lead to lengthy stalls. Kick off * unbound chain execution of currently pending work items. */ - wake_up_worker(pool); + kick_pool(pool); raw_spin_unlock_irq(&pool->lock); -- GitLab From 9546b29e4a6ad6ed7924dd7980975c8e675740a3 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:25 -1000 Subject: [PATCH 0897/3445] workqueue: Add workqueue_attrs->__pod_cpumask workqueue_attrs has two uses: * to specify the required unouned workqueue properties by users * to match worker_pool's properties to workqueues by core code For example, if the user wants to restrict a workqueue to run only CPUs 0 and 2, and the two CPUs are on different affinity scopes, the workqueue's attrs->cpumask would contains CPUs 0 and 2, and the workqueue would be associated with two worker_pools, one with attrs->cpumask containing just CPU 0 and the other CPU 2. Workqueue wants to support non-strict affinity scopes where work items are started in their matching affinity scopes but the scheduler is free to migrate them outside the starting scopes, which can enable utilizing the whole machine while maintaining most of the locality benefits from affinity scopes. To enable that, worker_pools need to distinguish the strict affinity that it has to follow (because that's the restriction coming from the user) and the soft affinity that it wants to apply when dispatching work items. Note that two worker_pools with different soft dispatching requirements have to be separate; otherwise, for example, we'd be ping-ponging worker threads across NUMA boundaries constantly. This patch adds workqueue_attrs->__pod_cpumask. The new field is double underscored as it's only used internally to distinguish worker_pools. A worker_pool's ->cpumask is now always the same as the online subset of allowed CPUs of the associated workqueues, and ->__pod_cpumask is the pod's subset of that ->cpumask. Going back to the example above, both worker_pools would have ->cpumask containing both CPUs 0 and 2 but one's ->__pod_cpumask would contain 0 while the other's 2. * pool_allowed_cpus() is added. It returns the worker_pool's strict cpumask that the pool's workers must stay within. This is currently always ->__pod_cpumask as all boundaries are still strict. * As a workqueue_attrs can now track both the associated workqueues' cpumask and its per-pod subset, wq_calc_pod_cpumask() no longer needs an external out-argument. Drop @cpumask and instead store the result in ->__pod_cpumask. * The above also simplifies apply_wqattrs_prepare() as the same workqueue_attrs can be used to create all pods associated with a workqueue. tmp_attrs is dropped. * wq_update_pod() is updated to use wqattrs_equal() to test whether a pwq update is needed instead of only comparing ->cpumask so that ->__pod_cpumask is compared too. It can directly compare ->__pod_cpumaks but the code is easier to understand and more robust this way. The only user-visible behavior change is that two workqueues with different cpumasks no longer can share worker_pools even when their pod subsets coincide. Going back to the example, let's say there's another workqueue with cpumask 0, 2, 3, where 2 and 3 are in the same pod. It would be mapped to two worker_pools - one with CPU 0, the other with 2 and 3. The former has the same cpumask as the first pod of the earlier example and would have shared the same worker_pool but that's no longer the case after this patch. The worker_pools would have the same ->__pod_cpumask but their ->cpumask's wouldn't match. While this is necessary to support non-strict affinity scopes, there can be further optimizations to maintain sharing among strict affinity scopes. However, non-strict affinity scopes are going to be preferable for most use cases and we don't see very diverse mixture of unbound workqueue cpumasks anyway, so the additional overhead doesn't seem to justify the extra complexity. v2: - wq_update_pod() was incorrectly comparing target_attrs->__pod_cpumask to pool->attrs->cpumask instead of its ->__pod_cpumask. Fix it by using wqattrs_equal() for comparison instead. - Per-cpu worker pools weren't initializing ->__pod_cpumask which caused a subtle problem later on. Set it to cpumask_of(cpu) like ->cpumask. Signed-off-by: Tejun Heo --- include/linux/workqueue.h | 16 +++++++++ kernel/workqueue.c | 74 +++++++++++++++++++-------------------- 2 files changed, 53 insertions(+), 37 deletions(-) diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 568cfbc24bc0f..fe53976e088eb 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -150,9 +150,25 @@ struct workqueue_attrs { /** * @cpumask: allowed CPUs + * + * Work items in this workqueue are affine to these CPUs and not allowed + * to execute on other CPUs. A pool serving a workqueue must have the + * same @cpumask. */ cpumask_var_t cpumask; + /** + * @__pod_cpumask: internal attribute used to create per-pod pools + * + * Internal use only. + * + * Per-pod unbound worker pools are used to improve locality. Always a + * subset of ->cpumask. A workqueue can be associated with multiple + * worker pools with disjoint @__pod_cpumask's. Whether the enforcement + * of a pool's @__pod_cpumask is strict depends on @affn_strict. + */ + cpumask_var_t __pod_cpumask; + /* * Below fields aren't properties of a worker_pool. They only modify how * :c:func:`apply_workqueue_attrs` select pools and thus don't diff --git a/kernel/workqueue.c b/kernel/workqueue.c index e941fa052a2bf..e61b4291bec85 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -366,7 +366,6 @@ static bool wq_online; /* can kworkers be created yet? */ /* buf for wq_update_unbound_pod_attrs(), protected by CPU hotplug exclusion */ static struct workqueue_attrs *wq_update_pod_attrs_buf; -static cpumask_var_t wq_update_pod_cpumask_buf; static DEFINE_MUTEX(wq_pool_mutex); /* protects pools and workqueues list */ static DEFINE_MUTEX(wq_pool_attach_mutex); /* protects worker attach/detach */ @@ -2050,6 +2049,11 @@ static struct worker *alloc_worker(int node) return worker; } +static cpumask_t *pool_allowed_cpus(struct worker_pool *pool) +{ + return pool->attrs->__pod_cpumask; +} + /** * worker_attach_to_pool() - attach a worker to a pool * @worker: worker to be attached @@ -2075,7 +2079,7 @@ static void worker_attach_to_pool(struct worker *worker, kthread_set_per_cpu(worker->task, pool->cpu); if (worker->rescue_wq) - set_cpus_allowed_ptr(worker->task, pool->attrs->cpumask); + set_cpus_allowed_ptr(worker->task, pool_allowed_cpus(pool)); list_add_tail(&worker->node, &pool->workers); worker->pool = pool; @@ -2167,7 +2171,7 @@ static struct worker *create_worker(struct worker_pool *pool) } set_user_nice(worker->task, pool->attrs->nice); - kthread_bind_mask(worker->task, pool->attrs->cpumask); + kthread_bind_mask(worker->task, pool_allowed_cpus(pool)); /* successful, attach the worker to the pool */ worker_attach_to_pool(worker, pool); @@ -3672,6 +3676,7 @@ void free_workqueue_attrs(struct workqueue_attrs *attrs) { if (attrs) { free_cpumask_var(attrs->cpumask); + free_cpumask_var(attrs->__pod_cpumask); kfree(attrs); } } @@ -3693,6 +3698,8 @@ struct workqueue_attrs *alloc_workqueue_attrs(void) goto fail; if (!alloc_cpumask_var(&attrs->cpumask, GFP_KERNEL)) goto fail; + if (!alloc_cpumask_var(&attrs->__pod_cpumask, GFP_KERNEL)) + goto fail; cpumask_copy(attrs->cpumask, cpu_possible_mask); attrs->affn_scope = wq_affn_dfl; @@ -3707,6 +3714,7 @@ static void copy_workqueue_attrs(struct workqueue_attrs *to, { to->nice = from->nice; cpumask_copy(to->cpumask, from->cpumask); + cpumask_copy(to->__pod_cpumask, from->__pod_cpumask); /* * Unlike hash and equality test, copying shouldn't ignore wq-only @@ -3735,6 +3743,8 @@ static u32 wqattrs_hash(const struct workqueue_attrs *attrs) hash = jhash_1word(attrs->nice, hash); hash = jhash(cpumask_bits(attrs->cpumask), BITS_TO_LONGS(nr_cpumask_bits) * sizeof(long), hash); + hash = jhash(cpumask_bits(attrs->__pod_cpumask), + BITS_TO_LONGS(nr_cpumask_bits) * sizeof(long), hash); return hash; } @@ -3746,6 +3756,8 @@ static bool wqattrs_equal(const struct workqueue_attrs *a, return false; if (!cpumask_equal(a->cpumask, b->cpumask)) return false; + if (!cpumask_equal(a->__pod_cpumask, b->__pod_cpumask)) + return false; return true; } @@ -3998,9 +4010,9 @@ static struct worker_pool *get_unbound_pool(const struct workqueue_attrs *attrs) } } - /* If cpumask is contained inside a NUMA pod, that's our NUMA node */ + /* If __pod_cpumask is contained inside a NUMA pod, that's our node */ for (pod = 0; pod < pt->nr_pods; pod++) { - if (cpumask_subset(attrs->cpumask, pt->pod_cpus[pod])) { + if (cpumask_subset(attrs->__pod_cpumask, pt->pod_cpus[pod])) { node = pt->pod_node[pod]; break; } @@ -4190,11 +4202,10 @@ static struct pool_workqueue *alloc_unbound_pwq(struct workqueue_struct *wq, * @attrs: the wq_attrs of the default pwq of the target workqueue * @cpu: the target CPU * @cpu_going_down: if >= 0, the CPU to consider as offline - * @cpumask: outarg, the resulting cpumask * * Calculate the cpumask a workqueue with @attrs should use on @pod. If * @cpu_going_down is >= 0, that cpu is considered offline during calculation. - * The result is stored in @cpumask. + * The result is stored in @attrs->__pod_cpumask. * * If pod affinity is not enabled, @attrs->cpumask is always used. If enabled * and @pod has online CPUs requested by @attrs, the returned cpumask is the @@ -4202,27 +4213,27 @@ static struct pool_workqueue *alloc_unbound_pwq(struct workqueue_struct *wq, * * The caller is responsible for ensuring that the cpumask of @pod stays stable. */ -static void wq_calc_pod_cpumask(const struct workqueue_attrs *attrs, int cpu, - int cpu_going_down, cpumask_t *cpumask) +static void wq_calc_pod_cpumask(struct workqueue_attrs *attrs, int cpu, + int cpu_going_down) { const struct wq_pod_type *pt = wqattrs_pod_type(attrs); int pod = pt->cpu_pod[cpu]; /* does @pod have any online CPUs @attrs wants? */ - cpumask_and(cpumask, pt->pod_cpus[pod], attrs->cpumask); - cpumask_and(cpumask, cpumask, cpu_online_mask); + cpumask_and(attrs->__pod_cpumask, pt->pod_cpus[pod], attrs->cpumask); + cpumask_and(attrs->__pod_cpumask, attrs->__pod_cpumask, cpu_online_mask); if (cpu_going_down >= 0) - cpumask_clear_cpu(cpu_going_down, cpumask); + cpumask_clear_cpu(cpu_going_down, attrs->__pod_cpumask); - if (cpumask_empty(cpumask)) { - cpumask_copy(cpumask, attrs->cpumask); + if (cpumask_empty(attrs->__pod_cpumask)) { + cpumask_copy(attrs->__pod_cpumask, attrs->cpumask); return; } /* yeap, return possible CPUs in @pod that @attrs wants */ - cpumask_and(cpumask, attrs->cpumask, pt->pod_cpus[pod]); + cpumask_and(attrs->__pod_cpumask, attrs->cpumask, pt->pod_cpus[pod]); - if (cpumask_empty(cpumask)) + if (cpumask_empty(attrs->__pod_cpumask)) pr_warn_once("WARNING: workqueue cpumask: online intersect > " "possible intersect\n"); } @@ -4276,7 +4287,7 @@ apply_wqattrs_prepare(struct workqueue_struct *wq, const cpumask_var_t unbound_cpumask) { struct apply_wqattrs_ctx *ctx; - struct workqueue_attrs *new_attrs, *tmp_attrs; + struct workqueue_attrs *new_attrs; int cpu; lockdep_assert_held(&wq_pool_mutex); @@ -4288,8 +4299,7 @@ apply_wqattrs_prepare(struct workqueue_struct *wq, ctx = kzalloc(struct_size(ctx, pwq_tbl, nr_cpu_ids), GFP_KERNEL); new_attrs = alloc_workqueue_attrs(); - tmp_attrs = alloc_workqueue_attrs(); - if (!ctx || !new_attrs || !tmp_attrs) + if (!ctx || !new_attrs) goto out_free; /* @@ -4299,23 +4309,18 @@ apply_wqattrs_prepare(struct workqueue_struct *wq, */ copy_workqueue_attrs(new_attrs, attrs); wqattrs_actualize_cpumask(new_attrs, unbound_cpumask); + cpumask_copy(new_attrs->__pod_cpumask, new_attrs->cpumask); ctx->dfl_pwq = alloc_unbound_pwq(wq, new_attrs); if (!ctx->dfl_pwq) goto out_free; - /* - * We may create multiple pwqs with differing cpumasks. Make a copy of - * @new_attrs which will be modified and used to obtain pools. - */ - copy_workqueue_attrs(tmp_attrs, new_attrs); - for_each_possible_cpu(cpu) { if (new_attrs->ordered) { ctx->dfl_pwq->refcnt++; ctx->pwq_tbl[cpu] = ctx->dfl_pwq; } else { - wq_calc_pod_cpumask(new_attrs, cpu, -1, tmp_attrs->cpumask); - ctx->pwq_tbl[cpu] = alloc_unbound_pwq(wq, tmp_attrs); + wq_calc_pod_cpumask(new_attrs, cpu, -1); + ctx->pwq_tbl[cpu] = alloc_unbound_pwq(wq, new_attrs); if (!ctx->pwq_tbl[cpu]) goto out_free; } @@ -4324,14 +4329,13 @@ apply_wqattrs_prepare(struct workqueue_struct *wq, /* save the user configured attrs and sanitize it. */ copy_workqueue_attrs(new_attrs, attrs); cpumask_and(new_attrs->cpumask, new_attrs->cpumask, cpu_possible_mask); + cpumask_copy(new_attrs->__pod_cpumask, new_attrs->cpumask); ctx->attrs = new_attrs; ctx->wq = wq; - free_workqueue_attrs(tmp_attrs); return ctx; out_free: - free_workqueue_attrs(tmp_attrs); free_workqueue_attrs(new_attrs); apply_wqattrs_cleanup(ctx); return ERR_PTR(-ENOMEM); @@ -4459,7 +4463,6 @@ static void wq_update_pod(struct workqueue_struct *wq, int cpu, int off_cpu = online ? -1 : hotplug_cpu; struct pool_workqueue *old_pwq = NULL, *pwq; struct workqueue_attrs *target_attrs; - cpumask_t *cpumask; lockdep_assert_held(&wq_pool_mutex); @@ -4472,20 +4475,18 @@ static void wq_update_pod(struct workqueue_struct *wq, int cpu, * CPU hotplug exclusion. */ target_attrs = wq_update_pod_attrs_buf; - cpumask = wq_update_pod_cpumask_buf; copy_workqueue_attrs(target_attrs, wq->unbound_attrs); wqattrs_actualize_cpumask(target_attrs, wq_unbound_cpumask); /* nothing to do if the target cpumask matches the current pwq */ - wq_calc_pod_cpumask(target_attrs, cpu, off_cpu, cpumask); + wq_calc_pod_cpumask(target_attrs, cpu, off_cpu); pwq = rcu_dereference_protected(*per_cpu_ptr(wq->cpu_pwq, cpu), lockdep_is_held(&wq_pool_mutex)); - if (cpumask_equal(cpumask, pwq->pool->attrs->cpumask)) + if (wqattrs_equal(target_attrs, pwq->pool->attrs)) return; /* create a new pwq */ - cpumask_copy(target_attrs->cpumask, cpumask); pwq = alloc_unbound_pwq(wq, target_attrs); if (!pwq) { pr_warn("workqueue: allocation failed while updating CPU pod affinity of \"%s\"\n", @@ -5409,7 +5410,7 @@ static void rebind_workers(struct worker_pool *pool) for_each_pool_worker(worker, pool) { kthread_set_per_cpu(worker->task, pool->cpu); WARN_ON_ONCE(set_cpus_allowed_ptr(worker->task, - pool->attrs->cpumask) < 0); + pool_allowed_cpus(pool)) < 0); } raw_spin_lock_irq(&pool->lock); @@ -6424,8 +6425,6 @@ void __init workqueue_init_early(void) wq_update_pod_attrs_buf = alloc_workqueue_attrs(); BUG_ON(!wq_update_pod_attrs_buf); - BUG_ON(!alloc_cpumask_var(&wq_update_pod_cpumask_buf, GFP_KERNEL)); - /* initialize WQ_AFFN_SYSTEM pods */ pt->pod_cpus = kcalloc(1, sizeof(pt->pod_cpus[0]), GFP_KERNEL); pt->pod_node = kcalloc(1, sizeof(pt->pod_node[0]), GFP_KERNEL); @@ -6451,6 +6450,7 @@ void __init workqueue_init_early(void) BUG_ON(init_worker_pool(pool)); pool->cpu = cpu; cpumask_copy(pool->attrs->cpumask, cpumask_of(cpu)); + cpumask_copy(pool->attrs->__pod_cpumask, cpumask_of(cpu)); pool->attrs->nice = std_nice[i++]; pool->node = cpu_to_node(cpu); -- GitLab From 8639ecebc9b1796d7074751a350462f5e1c61cd4 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:25 -1000 Subject: [PATCH 0898/3445] workqueue: Implement non-strict affinity scope for unbound workqueues An unbound workqueue can be served by multiple worker_pools to improve locality. The segmentation is achieved by grouping CPUs into pods. By default, the cache boundaries according to cpus_share_cache() define the CPUs are grouped. Let's a workqueue is allowed to run on all CPUs and the system has two L3 caches. The workqueue would be mapped to two worker_pools each serving one L3 cache domains. While this improves locality, because the pod boundaries are strict, it limits the total bandwidth a given issuer can consume. For example, let's say there is a thread pinned to a CPU issuing enough work items to saturate the whole machine. With the machine segmented into two pods, no matter how many work items it issues, it can only use half of the CPUs on the system. While this limitation has existed for a very long time, it wasn't very pronounced because the affinity grouping used to be always by NUMA nodes. With cache boundaries as the default and support for even finer grained scopes (smt and cpu), it is now an a lot more pressing problem. This patch implements non-strict affinity scope where the pod boundaries aren't enforced strictly. Going back to the previous example, the workqueue would still be mapped to two worker_pools; however, the affinity enforcement would be soft. The workers in both pools would have their cpus_allowed set to the whole machine thus allowing the scheduler to migrate them anywhere on the machine. However, whenever an idle worker is woken up, the workqueue code asks the scheduler to bring back the task within the pod if the worker is outside. ie. work items start executing within its affinity scope but can be migrated outside as the scheduler sees fit. This removes the hard cap on utilization while maintaining the benefits of affinity scopes. After the earlier ->__pod_cpumask changes, the implementation is pretty simple. When non-strict which is the new default: * pool_allowed_cpus() returns @pool->attrs->cpumask instead of ->__pod_cpumask so that the workers are allowed to run on any CPU that the associated workqueues allow. * If the idle worker task's ->wake_cpu is outside the pod, kick_pool() sets the field to a CPU within the pod. This would be the first use of task_struct->wake_cpu outside scheduler proper, so it isn't clear whether this would be acceptable. However, other methods of migrating tasks are significantly more expensive and are likely prohibitively so if we want to do this on every work item. This needs discussion with scheduler folks. There is also a race window where setting ->wake_cpu wouldn't be effective as the target task is still on CPU. However, the window is pretty small and this being a best-effort optimization, it doesn't seem to warrant more complexity at the moment. While the non-strict cache affinity scopes seem to be the best option, the performance picture interacts with the affinity scope and is a bit complicated to fully discuss in this patch, so the behavior is made easily selectable through wqattrs and sysfs and the next patch will add documentation to discuss performance implications. v2: pool->attrs->affn_strict is set to true for per-cpu worker_pools. Signed-off-by: Tejun Heo Cc: Peter Zijlstra Cc: Linus Torvalds --- Documentation/core-api/workqueue.rst | 30 ++++++++--- include/linux/workqueue.h | 11 +++++ kernel/workqueue.c | 74 +++++++++++++++++++++++++++- tools/workqueue/wq_dump.py | 16 ++++-- tools/workqueue/wq_monitor.py | 21 +++++--- 5 files changed, 132 insertions(+), 20 deletions(-) diff --git a/Documentation/core-api/workqueue.rst b/Documentation/core-api/workqueue.rst index 56af317508c9c..c73a6df6a1187 100644 --- a/Documentation/core-api/workqueue.rst +++ b/Documentation/core-api/workqueue.rst @@ -353,9 +353,10 @@ Affinity Scopes An unbound workqueue groups CPUs according to its affinity scope to improve cache locality. For example, if a workqueue is using the default affinity scope of "cache", it will group CPUs according to last level cache -boundaries. A work item queued on the workqueue will be processed by a -worker running on one of the CPUs which share the last level cache with the -issuing CPU. +boundaries. A work item queued on the workqueue will be assigned to a worker +on one of the CPUs which share the last level cache with the issuing CPU. +Once started, the worker may or may not be allowed to move outside the scope +depending on the ``affinity_strict`` setting of the scope. Workqueue currently supports the following five affinity scopes. @@ -391,6 +392,21 @@ directory. ``affinity_scope`` Read to see the current affinity scope. Write to change. +``affinity_strict`` + 0 by default indicating that affinity scopes are not strict. When a work + item starts execution, workqueue makes a best-effort attempt to ensure + that the worker is inside its affinity scope, which is called + repatriation. Once started, the scheduler is free to move the worker + anywhere in the system as it sees fit. This enables benefiting from scope + locality while still being able to utilize other CPUs if necessary and + available. + + If set to 1, all workers of the scope are guaranteed always to be in the + scope. This may be useful when crossing affinity scopes has other + implications, for example, in terms of power consumption or workload + isolation. Strict NUMA scope can also be used to match the workqueue + behavior of older kernels. + Examining Configuration ======================= @@ -475,21 +491,21 @@ Monitoring Use tools/workqueue/wq_monitor.py to monitor workqueue operations: :: $ tools/workqueue/wq_monitor.py events - total infl CPUtime CPUhog CMwake mayday rescued + total infl CPUtime CPUhog CMW/RPR mayday rescued events 18545 0 6.1 0 5 - - events_highpri 8 0 0.0 0 0 - - events_long 3 0 0.0 0 0 - - - events_unbound 38306 0 0.1 - - - - + events_unbound 38306 0 0.1 - 7 - - events_freezable 0 0 0.0 0 0 - - events_power_efficient 29598 0 0.2 0 0 - - events_freezable_power_ 10 0 0.0 0 0 - - sock_diag_events 0 0 0.0 0 0 - - - total infl CPUtime CPUhog CMwake mayday rescued + total infl CPUtime CPUhog CMW/RPR mayday rescued events 18548 0 6.1 0 5 - - events_highpri 8 0 0.0 0 0 - - events_long 3 0 0.0 0 0 - - - events_unbound 38322 0 0.1 - - - - + events_unbound 38322 0 0.1 - 7 - - events_freezable 0 0 0.0 0 0 - - events_power_efficient 29603 0 0.2 0 0 - - events_freezable_power_ 10 0 0.0 0 0 - - diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index fe53976e088eb..0c1cad38f9db6 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -169,6 +169,17 @@ struct workqueue_attrs { */ cpumask_var_t __pod_cpumask; + /** + * @affn_strict: affinity scope is strict + * + * If clear, workqueue will make a best-effort attempt at starting the + * worker inside @__pod_cpumask but the scheduler is free to migrate it + * outside. + * + * If set, workers are only allowed to run inside @__pod_cpumask. + */ + bool affn_strict; + /* * Below fields aren't properties of a worker_pool. They only modify how * :c:func:`apply_workqueue_attrs` select pools and thus don't diff --git a/kernel/workqueue.c b/kernel/workqueue.c index e61b4291bec85..6f6f4f37ceb32 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -211,6 +211,7 @@ enum pool_workqueue_stats { PWQ_STAT_CPU_TIME, /* total CPU time consumed */ PWQ_STAT_CPU_INTENSIVE, /* wq_cpu_intensive_thresh_us violations */ PWQ_STAT_CM_WAKEUP, /* concurrency-management worker wakeups */ + PWQ_STAT_REPATRIATED, /* unbound workers brought back into scope */ PWQ_STAT_MAYDAY, /* maydays to rescuer */ PWQ_STAT_RESCUED, /* linked work items executed by rescuer */ @@ -1103,13 +1104,41 @@ static bool assign_work(struct work_struct *work, struct worker *worker, static bool kick_pool(struct worker_pool *pool) { struct worker *worker = first_idle_worker(pool); + struct task_struct *p; lockdep_assert_held(&pool->lock); if (!need_more_worker(pool) || !worker) return false; - wake_up_process(worker->task); + p = worker->task; + +#ifdef CONFIG_SMP + /* + * Idle @worker is about to execute @work and waking up provides an + * opportunity to migrate @worker at a lower cost by setting the task's + * wake_cpu field. Let's see if we want to move @worker to improve + * execution locality. + * + * We're waking the worker that went idle the latest and there's some + * chance that @worker is marked idle but hasn't gone off CPU yet. If + * so, setting the wake_cpu won't do anything. As this is a best-effort + * optimization and the race window is narrow, let's leave as-is for + * now. If this becomes pronounced, we can skip over workers which are + * still on cpu when picking an idle worker. + * + * If @pool has non-strict affinity, @worker might have ended up outside + * its affinity scope. Repatriate. + */ + if (!pool->attrs->affn_strict && + !cpumask_test_cpu(p->wake_cpu, pool->attrs->__pod_cpumask)) { + struct work_struct *work = list_first_entry(&pool->worklist, + struct work_struct, entry); + p->wake_cpu = cpumask_any_distribute(pool->attrs->__pod_cpumask); + get_work_pwq(work)->stats[PWQ_STAT_REPATRIATED]++; + } +#endif + wake_up_process(p); return true; } @@ -2051,7 +2080,10 @@ static struct worker *alloc_worker(int node) static cpumask_t *pool_allowed_cpus(struct worker_pool *pool) { - return pool->attrs->__pod_cpumask; + if (pool->cpu < 0 && pool->attrs->affn_strict) + return pool->attrs->__pod_cpumask; + else + return pool->attrs->cpumask; } /** @@ -3715,6 +3747,7 @@ static void copy_workqueue_attrs(struct workqueue_attrs *to, to->nice = from->nice; cpumask_copy(to->cpumask, from->cpumask); cpumask_copy(to->__pod_cpumask, from->__pod_cpumask); + to->affn_strict = from->affn_strict; /* * Unlike hash and equality test, copying shouldn't ignore wq-only @@ -3745,6 +3778,7 @@ static u32 wqattrs_hash(const struct workqueue_attrs *attrs) BITS_TO_LONGS(nr_cpumask_bits) * sizeof(long), hash); hash = jhash(cpumask_bits(attrs->__pod_cpumask), BITS_TO_LONGS(nr_cpumask_bits) * sizeof(long), hash); + hash = jhash_1word(attrs->affn_strict, hash); return hash; } @@ -3758,6 +3792,8 @@ static bool wqattrs_equal(const struct workqueue_attrs *a, return false; if (!cpumask_equal(a->__pod_cpumask, b->__pod_cpumask)) return false; + if (a->affn_strict != b->affn_strict) + return false; return true; } @@ -5847,6 +5883,7 @@ module_param_cb(default_affinity_scope, &wq_affn_dfl_ops, NULL, 0644); * nice RW int : nice value of the workers * cpumask RW mask : bitmask of allowed CPUs for the workers * affinity_scope RW str : worker CPU affinity scope (cache, numa, none) + * affinity_strict RW bool : worker CPU affinity is strict */ struct wq_device { struct workqueue_struct *wq; @@ -6026,10 +6063,42 @@ static ssize_t wq_affn_scope_store(struct device *dev, return ret ?: count; } +static ssize_t wq_affinity_strict_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct workqueue_struct *wq = dev_to_wq(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", + wq->unbound_attrs->affn_strict); +} + +static ssize_t wq_affinity_strict_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct workqueue_struct *wq = dev_to_wq(dev); + struct workqueue_attrs *attrs; + int v, ret = -ENOMEM; + + if (sscanf(buf, "%d", &v) != 1) + return -EINVAL; + + apply_wqattrs_lock(); + attrs = wq_sysfs_prep_attrs(wq); + if (attrs) { + attrs->affn_strict = (bool)v; + ret = apply_workqueue_attrs_locked(wq, attrs); + } + apply_wqattrs_unlock(); + free_workqueue_attrs(attrs); + return ret ?: count; +} + static struct device_attribute wq_sysfs_unbound_attrs[] = { __ATTR(nice, 0644, wq_nice_show, wq_nice_store), __ATTR(cpumask, 0644, wq_cpumask_show, wq_cpumask_store), __ATTR(affinity_scope, 0644, wq_affn_scope_show, wq_affn_scope_store), + __ATTR(affinity_strict, 0644, wq_affinity_strict_show, wq_affinity_strict_store), __ATTR_NULL, }; @@ -6452,6 +6521,7 @@ void __init workqueue_init_early(void) cpumask_copy(pool->attrs->cpumask, cpumask_of(cpu)); cpumask_copy(pool->attrs->__pod_cpumask, cpumask_of(cpu)); pool->attrs->nice = std_nice[i++]; + pool->attrs->affn_strict = true; pool->node = cpu_to_node(cpu); /* alloc pool ID */ diff --git a/tools/workqueue/wq_dump.py b/tools/workqueue/wq_dump.py index 43ab71a193b83..d0df5833f2c18 100644 --- a/tools/workqueue/wq_dump.py +++ b/tools/workqueue/wq_dump.py @@ -36,10 +36,11 @@ Workqueue CPU -> pool Lists all workqueues along with their type and worker pool association. For each workqueue: - NAME TYPE POOL_ID... + NAME TYPE[,FLAGS] POOL_ID... NAME name of the workqueue TYPE percpu, unbound or ordered + FLAGS S: strict affinity scope POOL_ID worker pool ID associated with each possible CPU """ @@ -138,13 +139,16 @@ for pi, pool in idr_for_each(worker_pool_idr): print(f'cpu={pool.cpu.value_():3}', end='') else: print(f'cpus={cpumask_str(pool.attrs.cpumask)}', end='') + print(f' pod_cpus={cpumask_str(pool.attrs.__pod_cpumask)}', end='') + if pool.attrs.affn_strict: + print(' strict', end='') print('') print('') print('Workqueue CPU -> pool') print('=====================') -print('[ workqueue \ CPU ', end='') +print('[ workqueue \ type CPU', end='') for cpu in for_each_possible_cpu(prog): print(f' {cpu:{max_pool_id_len}}', end='') print(' dfl]') @@ -153,11 +157,15 @@ for wq in list_for_each_entry('struct workqueue_struct', workqueues.address_of_( print(f'{wq.name.string_().decode()[-24:]:24}', end='') if wq.flags & WQ_UNBOUND: if wq.flags & WQ_ORDERED: - print(' ordered', end='') + print(' ordered ', end='') else: print(' unbound', end='') + if wq.unbound_attrs.affn_strict: + print(',S ', end='') + else: + print(' ', end='') else: - print(' percpu ', end='') + print(' percpu ', end='') for cpu in for_each_possible_cpu(prog): pool_id = per_cpu_ptr(wq.cpu_pwq, cpu)[0].pool.id.value_() diff --git a/tools/workqueue/wq_monitor.py b/tools/workqueue/wq_monitor.py index 6e258d123e8c7..a8856a9c45dcc 100644 --- a/tools/workqueue/wq_monitor.py +++ b/tools/workqueue/wq_monitor.py @@ -20,8 +20,11 @@ https://github.com/osandov/drgn. and got excluded from concurrency management to avoid stalling other work items. - CMwake The number of concurrency-management wake-ups while executing a - work item of the workqueue. + CMW/RPR For per-cpu workqueues, the number of concurrency-management + wake-ups while executing a work item of the workqueue. For + unbound workqueues, the number of times a worker was repatriated + to its affinity scope after being migrated to an off-scope CPU by + the scheduler. mayday The number of times the rescuer was requested while waiting for new worker creation. @@ -65,6 +68,7 @@ PWQ_STAT_COMPLETED = prog['PWQ_STAT_COMPLETED'] # work items completed exec PWQ_STAT_CPU_TIME = prog['PWQ_STAT_CPU_TIME'] # total CPU time consumed PWQ_STAT_CPU_INTENSIVE = prog['PWQ_STAT_CPU_INTENSIVE'] # wq_cpu_intensive_thresh_us violations PWQ_STAT_CM_WAKEUP = prog['PWQ_STAT_CM_WAKEUP'] # concurrency-management worker wakeups +PWQ_STAT_REPATRIATED = prog['PWQ_STAT_REPATRIATED'] # unbound workers brought back into scope PWQ_STAT_MAYDAY = prog['PWQ_STAT_MAYDAY'] # maydays to rescuer PWQ_STAT_RESCUED = prog['PWQ_STAT_RESCUED'] # linked work items executed by rescuer PWQ_NR_STATS = prog['PWQ_NR_STATS'] @@ -89,22 +93,25 @@ class WqStats: 'cpu_time' : self.stats[PWQ_STAT_CPU_TIME], 'cpu_intensive' : self.stats[PWQ_STAT_CPU_INTENSIVE], 'cm_wakeup' : self.stats[PWQ_STAT_CM_WAKEUP], + 'repatriated' : self.stats[PWQ_STAT_REPATRIATED], 'mayday' : self.stats[PWQ_STAT_MAYDAY], 'rescued' : self.stats[PWQ_STAT_RESCUED], } def table_header_str(): return f'{"":>24} {"total":>8} {"infl":>5} {"CPUtime":>8} '\ - f'{"CPUitsv":>7} {"CMwake":>7} {"mayday":>7} {"rescued":>7}' + f'{"CPUitsv":>7} {"CMW/RPR":>7} {"mayday":>7} {"rescued":>7}' def table_row_str(self): cpu_intensive = '-' - cm_wakeup = '-' + cmw_rpr = '-' mayday = '-' rescued = '-' - if not self.unbound: + if self.unbound: + cmw_rpr = str(self.stats[PWQ_STAT_REPATRIATED]); + else: cpu_intensive = str(self.stats[PWQ_STAT_CPU_INTENSIVE]) - cm_wakeup = str(self.stats[PWQ_STAT_CM_WAKEUP]) + cmw_rpr = str(self.stats[PWQ_STAT_CM_WAKEUP]) if self.mem_reclaim: mayday = str(self.stats[PWQ_STAT_MAYDAY]) @@ -115,7 +122,7 @@ class WqStats: f'{max(self.stats[PWQ_STAT_STARTED] - self.stats[PWQ_STAT_COMPLETED], 0):5} ' \ f'{self.stats[PWQ_STAT_CPU_TIME] / 1000000:8.1f} ' \ f'{cpu_intensive:>7} ' \ - f'{cm_wakeup:>7} ' \ + f'{cmw_rpr:>7} ' \ f'{mayday:>7} ' \ f'{rescued:>7} ' return out.rstrip(':') -- GitLab From 7dbf15c5c05e835d488e0fee49a35b0f23452e45 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:25 -1000 Subject: [PATCH 0899/3445] workqueue: Add "Affinity Scopes and Performance" section to documentation With affinity scopes and their strictness setting added, unbound workqueues should now be able to cover wide variety of configurations and use cases. Unfortunately, the performance picture is not entirely straight-forward due to a trade-off between efficiency and work-conservation in some situations necessitating manual configuration. This patch adds "Affinity Scopes and Performance" section to Documentation/core-api/workqueue.rst which illustrates the trade-off with a set of experiments and provides some guidelines. Signed-off-by: Tejun Heo --- Documentation/core-api/workqueue.rst | 184 ++++++++++++++++++++++++++- 1 file changed, 179 insertions(+), 5 deletions(-) diff --git a/Documentation/core-api/workqueue.rst b/Documentation/core-api/workqueue.rst index c73a6df6a1187..4a8e764f41aea 100644 --- a/Documentation/core-api/workqueue.rst +++ b/Documentation/core-api/workqueue.rst @@ -1,6 +1,6 @@ -==================================== -Concurrency Managed Workqueue (cmwq) -==================================== +========= +Workqueue +========= :Date: September, 2010 :Author: Tejun Heo @@ -25,8 +25,8 @@ there is no work item left on the workqueue the worker becomes idle. When a new work item gets queued, the worker begins executing again. -Why cmwq? -========= +Why Concurrency Managed Workqueue? +================================== In the original wq implementation, a multi threaded (MT) wq had one worker thread per CPU and a single threaded (ST) wq had one worker @@ -408,6 +408,180 @@ directory. behavior of older kernels. +Affinity Scopes and Performance +=============================== + +It'd be ideal if an unbound workqueue's behavior is optimal for vast +majority of use cases without further tuning. Unfortunately, in the current +kernel, there exists a pronounced trade-off between locality and utilization +necessitating explicit configurations when workqueues are heavily used. + +Higher locality leads to higher efficiency where more work is performed for +the same number of consumed CPU cycles. However, higher locality may also +cause lower overall system utilization if the work items are not spread +enough across the affinity scopes by the issuers. The following performance +testing with dm-crypt clearly illustrates this trade-off. + +The tests are run on a CPU with 12-cores/24-threads split across four L3 +caches (AMD Ryzen 9 3900x). CPU clock boost is turned off for consistency. +``/dev/dm-0`` is a dm-crypt device created on NVME SSD (Samsung 990 PRO) and +opened with ``cryptsetup`` with default settings. + + +Scenario 1: Enough issuers and work spread across the machine +------------------------------------------------------------- + +The command used: :: + + $ fio --filename=/dev/dm-0 --direct=1 --rw=randrw --bs=32k --ioengine=libaio \ + --iodepth=64 --runtime=60 --numjobs=24 --time_based --group_reporting \ + --name=iops-test-job --verify=sha512 + +There are 24 issuers, each issuing 64 IOs concurrently. ``--verify=sha512`` +makes ``fio`` generate and read back the content each time which makes +execution locality matter between the issuer and ``kcryptd``. The followings +are the read bandwidths and CPU utilizations depending on different affinity +scope settings on ``kcryptd`` measured over five runs. Bandwidths are in +MiBps, and CPU util in percents. + +.. list-table:: + :widths: 16 20 20 + :header-rows: 1 + + * - Affinity + - Bandwidth (MiBps) + - CPU util (%) + + * - system + - 1159.40 ±1.34 + - 99.31 ±0.02 + + * - cache + - 1166.40 ±0.89 + - 99.34 ±0.01 + + * - cache (strict) + - 1166.00 ±0.71 + - 99.35 ±0.01 + +With enough issuers spread across the system, there is no downside to +"cache", strict or otherwise. All three configurations saturate the whole +machine but the cache-affine ones outperform by 0.6% thanks to improved +locality. + + +Scenario 2: Fewer issuers, enough work for saturation +----------------------------------------------------- + +The command used: :: + + $ fio --filename=/dev/dm-0 --direct=1 --rw=randrw --bs=32k \ + --ioengine=libaio --iodepth=64 --runtime=60 --numjobs=8 \ + --time_based --group_reporting --name=iops-test-job --verify=sha512 + +The only difference from the previous scenario is ``--numjobs=8``. There are +a third of the issuers but is still enough total work to saturate the +system. + +.. list-table:: + :widths: 16 20 20 + :header-rows: 1 + + * - Affinity + - Bandwidth (MiBps) + - CPU util (%) + + * - system + - 1155.40 ±0.89 + - 97.41 ±0.05 + + * - cache + - 1154.40 ±1.14 + - 96.15 ±0.09 + + * - cache (strict) + - 1112.00 ±4.64 + - 93.26 ±0.35 + +This is more than enough work to saturate the system. Both "system" and +"cache" are nearly saturating the machine but not fully. "cache" is using +less CPU but the better efficiency puts it at the same bandwidth as +"system". + +Eight issuers moving around over four L3 cache scope still allow "cache +(strict)" to mostly saturate the machine but the loss of work conservation +is now starting to hurt with 3.7% bandwidth loss. + + +Scenario 3: Even fewer issuers, not enough work to saturate +----------------------------------------------------------- + +The command used: :: + + $ fio --filename=/dev/dm-0 --direct=1 --rw=randrw --bs=32k \ + --ioengine=libaio --iodepth=64 --runtime=60 --numjobs=4 \ + --time_based --group_reporting --name=iops-test-job --verify=sha512 + +Again, the only difference is ``--numjobs=4``. With the number of issuers +reduced to four, there now isn't enough work to saturate the whole system +and the bandwidth becomes dependent on completion latencies. + +.. list-table:: + :widths: 16 20 20 + :header-rows: 1 + + * - Affinity + - Bandwidth (MiBps) + - CPU util (%) + + * - system + - 993.60 ±1.82 + - 75.49 ±0.06 + + * - cache + - 973.40 ±1.52 + - 74.90 ±0.07 + + * - cache (strict) + - 828.20 ±4.49 + - 66.84 ±0.29 + +Now, the tradeoff between locality and utilization is clearer. "cache" shows +2% bandwidth loss compared to "system" and "cache (struct)" whopping 20%. + + +Conclusion and Recommendations +------------------------------ + +In the above experiments, the efficiency advantage of the "cache" affinity +scope over "system" is, while consistent and noticeable, small. However, the +impact is dependent on the distances between the scopes and may be more +pronounced in processors with more complex topologies. + +While the loss of work-conservation in certain scenarios hurts, it is a lot +better than "cache (strict)" and maximizing workqueue utilization is +unlikely to be the common case anyway. As such, "cache" is the default +affinity scope for unbound pools. + +* As there is no one option which is great for most cases, workqueue usages + that may consume a significant amount of CPU are recommended to configure + the workqueues using ``apply_workqueue_attrs()`` and/or enable + ``WQ_SYSFS``. + +* An unbound workqueue with strict "cpu" affinity scope behaves the same as + ``WQ_CPU_INTENSIVE`` per-cpu workqueue. There is no real advanage to the + latter and an unbound workqueue provides a lot more flexibility. + +* Affinity scopes are introduced in Linux v6.5. To emulate the previous + behavior, use strict "numa" affinity scope. + +* The loss of work-conservation in non-strict affinity scopes is likely + originating from the scheduler. There is no theoretical reason why the + kernel wouldn't be able to do the right thing and maintain + work-conservation in most cases. As such, it is possible that future + scheduler improvements may make most of these tunables unnecessary. + + Examining Configuration ======================= -- GitLab From 523a301e66afd1ea9856660bcf3cee3a7c84c6dd Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 7 Aug 2023 15:57:25 -1000 Subject: [PATCH 0900/3445] workqueue: Make default affinity_scope dynamically updatable While workqueue.default_affinity_scope is writable, it only affects workqueues which are created afterwards and isn't very useful. Instead, let's introduce explicit "default" scope and update the effective scope dynamically when workqueue.default_affinity_scope is changed. Signed-off-by: Tejun Heo --- .../admin-guide/kernel-parameters.txt | 8 ++-- Documentation/core-api/workqueue.rst | 9 +++- include/linux/workqueue.h | 3 +- kernel/workqueue.c | 45 ++++++++++++++++--- 4 files changed, 52 insertions(+), 13 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 732c5c7e3fa54..98ffce100a391 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -7014,10 +7014,10 @@ information, see the Affinity Scopes section in Documentation/core-api/workqueue.rst. - This can be updated after boot through the matching - file under /sys/module/workqueue/parameters. - However, the changed default will only apply to - unbound workqueues created afterwards. + This can be changed after boot by writing to the + matching /sys/module/workqueue/parameters file. All + workqueues with the "default" affinity scope will be + updated accordignly. workqueue.debug_force_rr_cpu Workqueue used to implicitly guarantee that work diff --git a/Documentation/core-api/workqueue.rst b/Documentation/core-api/workqueue.rst index 4a8e764f41aea..5d7b01aed1fe6 100644 --- a/Documentation/core-api/workqueue.rst +++ b/Documentation/core-api/workqueue.rst @@ -358,7 +358,11 @@ on one of the CPUs which share the last level cache with the issuing CPU. Once started, the worker may or may not be allowed to move outside the scope depending on the ``affinity_strict`` setting of the scope. -Workqueue currently supports the following five affinity scopes. +Workqueue currently supports the following affinity scopes. + +``default`` + Use the scope in module parameter ``workqueue.default_affinity_scope`` + which is always set to one of the scopes below. ``cpu`` CPUs are not grouped. A work item issued on one CPU is processed by a @@ -392,6 +396,9 @@ directory. ``affinity_scope`` Read to see the current affinity scope. Write to change. + When default is the current scope, reading this file will also show the + current effective scope in parentheses, for example, ``default (cache)``. + ``affinity_strict`` 0 by default indicating that affinity scopes are not strict. When a work item starts execution, workqueue makes a best-effort attempt to ensure diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 0c1cad38f9db6..1c1d06804d450 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -126,6 +126,7 @@ struct rcu_work { }; enum wq_affn_scope { + WQ_AFFN_DFL, /* use system default */ WQ_AFFN_CPU, /* one pod per CPU */ WQ_AFFN_SMT, /* one pod poer SMT */ WQ_AFFN_CACHE, /* one pod per LLC */ @@ -133,8 +134,6 @@ enum wq_affn_scope { WQ_AFFN_SYSTEM, /* one pod across the whole system */ WQ_AFFN_NR_TYPES, - - WQ_AFFN_DFL = WQ_AFFN_CACHE, }; /** diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 6f6f4f37ceb32..789e11e72a4a4 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -339,9 +339,10 @@ struct wq_pod_type { }; static struct wq_pod_type wq_pod_types[WQ_AFFN_NR_TYPES]; -static enum wq_affn_scope wq_affn_dfl = WQ_AFFN_DFL; +static enum wq_affn_scope wq_affn_dfl = WQ_AFFN_CACHE; static const char *wq_affn_names[WQ_AFFN_NR_TYPES] = { + [WQ_AFFN_DFL] = "default", [WQ_AFFN_CPU] = "cpu", [WQ_AFFN_SMT] = "smt", [WQ_AFFN_CACHE] = "cache", @@ -3734,7 +3735,7 @@ struct workqueue_attrs *alloc_workqueue_attrs(void) goto fail; cpumask_copy(attrs->cpumask, cpu_possible_mask); - attrs->affn_scope = wq_affn_dfl; + attrs->affn_scope = WQ_AFFN_DFL; return attrs; fail: free_workqueue_attrs(attrs); @@ -3815,7 +3816,18 @@ static void wqattrs_actualize_cpumask(struct workqueue_attrs *attrs, static const struct wq_pod_type * wqattrs_pod_type(const struct workqueue_attrs *attrs) { - struct wq_pod_type *pt = &wq_pod_types[attrs->affn_scope]; + enum wq_affn_scope scope; + struct wq_pod_type *pt; + + /* to synchronize access to wq_affn_dfl */ + lockdep_assert_held(&wq_pool_mutex); + + if (attrs->affn_scope == WQ_AFFN_DFL) + scope = wq_affn_dfl; + else + scope = attrs->affn_scope; + + pt = &wq_pod_types[scope]; if (!WARN_ON_ONCE(attrs->affn_scope == WQ_AFFN_NR_TYPES) && likely(pt->nr_pods)) @@ -5847,13 +5859,29 @@ static int parse_affn_scope(const char *val) static int wq_affn_dfl_set(const char *val, const struct kernel_param *kp) { - int affn; + struct workqueue_struct *wq; + int affn, cpu; affn = parse_affn_scope(val); if (affn < 0) return affn; + if (affn == WQ_AFFN_DFL) + return -EINVAL; + + cpus_read_lock(); + mutex_lock(&wq_pool_mutex); wq_affn_dfl = affn; + + list_for_each_entry(wq, &workqueues, list) { + for_each_online_cpu(cpu) { + wq_update_pod(wq, cpu, cpu, true); + } + } + + mutex_unlock(&wq_pool_mutex); + cpus_read_unlock(); + return 0; } @@ -6033,8 +6061,13 @@ static ssize_t wq_affn_scope_show(struct device *dev, int written; mutex_lock(&wq->mutex); - written = scnprintf(buf, PAGE_SIZE, "%s\n", - wq_affn_names[wq->unbound_attrs->affn_scope]); + if (wq->unbound_attrs->affn_scope == WQ_AFFN_DFL) + written = scnprintf(buf, PAGE_SIZE, "%s (%s)\n", + wq_affn_names[WQ_AFFN_DFL], + wq_affn_names[wq_affn_dfl]); + else + written = scnprintf(buf, PAGE_SIZE, "%s\n", + wq_affn_names[wq->unbound_attrs->affn_scope]); mutex_unlock(&wq->mutex); return written; -- GitLab From a18e81d17a7e634420e589fa504e79e4893cde5e Mon Sep 17 00:00:00 2001 From: Jeuk Kim Date: Mon, 7 Aug 2023 10:37:26 +0900 Subject: [PATCH 0901/3445] scsi: ufs: ufs-pci: Add support for QEMU To ensure that the PCI based QEMU UFS device properly works with Linux, register the device ID (0x0013) and vendor ID (0x1b36) of QEMU UFS device. QEMU UFS will enable testing of the UFS driver inside a virtual machine on systems without UFS host controller. It can also be used to preemptively implement and test new features before the real device is created. The new QEMU UFS device can be found at: https://lore.kernel.org/qemu-devel/20230727155239.GA979354@fedora Signed-off-by: Jeuk Kim Link: https://lore.kernel.org/r/20230807013726epcms2p1c604cb8e98680aebebb7cc5ab2d580f5@epcms2p1 Acked-by: Adrian Hunter Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufshcd-pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ufs/host/ufshcd-pci.c b/drivers/ufs/host/ufshcd-pci.c index 95df8105265ab..248a49e5e7f35 100644 --- a/drivers/ufs/host/ufshcd-pci.c +++ b/drivers/ufs/host/ufshcd-pci.c @@ -590,6 +590,7 @@ static const struct dev_pm_ops ufshcd_pci_pm_ops = { }; static const struct pci_device_id ufshcd_pci_tbl[] = { + { PCI_VENDOR_ID_REDHAT, 0x0013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VDEVICE(INTEL, 0x9DFA), (kernel_ulong_t)&ufs_intel_cnl_hba_vops }, { PCI_VDEVICE(INTEL, 0x4B41), (kernel_ulong_t)&ufs_intel_ehl_hba_vops }, -- GitLab From 8e11876a1127f27c5e5e07072bfc590e53509a84 Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Mon, 19 Jun 2023 13:19:08 +0000 Subject: [PATCH 0902/3445] iommu/amd: Rearrange DTE bit definations Rearrage according to 64bit word they are in. Note that I have not rearranged gcr3 related macros even though they belong to different 64bit word as its easy to read it in current format. No functional changes intended. Suggested-by: Jerry Snitselaar Signed-off-by: Vasant Hegde Reviewed-by: Jerry Snitselaar Link: https://lore.kernel.org/r/20230619131908.5887-1-vasant.hegde@amd.com Signed-off-by: Joerg Roedel --- drivers/iommu/amd/amd_iommu_types.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index 781ab9c2ea70d..7dc30c2b56b30 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -384,15 +384,15 @@ */ #define DTE_FLAG_V BIT_ULL(0) #define DTE_FLAG_TV BIT_ULL(1) +#define DTE_FLAG_GIOV BIT_ULL(54) +#define DTE_FLAG_GV BIT_ULL(55) +#define DTE_GLX_SHIFT (56) +#define DTE_GLX_MASK (3) #define DTE_FLAG_IR BIT_ULL(61) #define DTE_FLAG_IW BIT_ULL(62) #define DTE_FLAG_IOTLB BIT_ULL(32) -#define DTE_FLAG_GIOV BIT_ULL(54) -#define DTE_FLAG_GV BIT_ULL(55) #define DTE_FLAG_MASK (0x3ffULL << 32) -#define DTE_GLX_SHIFT (56) -#define DTE_GLX_MASK (3) #define DEV_DOMID_MASK 0xffffULL #define DTE_GCR3_VAL_A(x) (((x) >> 12) & 0x00007ULL) -- GitLab From 64917f4c35b3e490e0c0f966fab533dfb560db5e Mon Sep 17 00:00:00 2001 From: Ivan Orlov Date: Fri, 4 Aug 2023 17:05:28 +0200 Subject: [PATCH 0903/3445] RDMA: Make all 'class' structures const Now that the driver core allows for struct class to be in read-only memory, making all 'class' structures to be declared at build time placing them into read-only memory, instead of having to be dynamically allocated at load time. Cc: Jason Gunthorpe Cc: Leon Romanovsky Cc: Dennis Dalessandro Cc: "Md. Haris Iqbal" Cc: Jack Wang Cc: Greg Kroah-Hartman Cc: Yishai Hadas Cc: Ivan Orlov Cc: Benjamin Tissoires Suggested-by: Greg Kroah-Hartman Signed-off-by: Ivan Orlov Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/2023080427-commuting-crewless-cbee@gregkh Signed-off-by: Leon Romanovsky --- drivers/infiniband/core/uverbs_main.c | 35 +++++----- drivers/infiniband/hw/hfi1/device.c | 72 +++++++++----------- drivers/infiniband/hw/qib/qib_file_ops.c | 17 +++-- drivers/infiniband/ulp/rtrs/rtrs-clt.c | 19 +++--- drivers/infiniband/ulp/rtrs/rtrs-srv-sysfs.c | 2 +- drivers/infiniband/ulp/rtrs/rtrs-srv.c | 15 ++-- drivers/infiniband/ulp/rtrs/rtrs-srv.h | 2 +- 7 files changed, 79 insertions(+), 83 deletions(-) diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 7c9c79c139411..bf800f8cb3e4b 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -72,12 +72,23 @@ enum { #define IB_UVERBS_BASE_DEV MKDEV(IB_UVERBS_MAJOR, IB_UVERBS_BASE_MINOR) static dev_t dynamic_uverbs_dev; -static struct class *uverbs_class; static DEFINE_IDA(uverbs_ida); static int ib_uverbs_add_one(struct ib_device *device); static void ib_uverbs_remove_one(struct ib_device *device, void *client_data); +static char *uverbs_devnode(const struct device *dev, umode_t *mode) +{ + if (mode) + *mode = 0666; + return kasprintf(GFP_KERNEL, "infiniband/%s", dev_name(dev)); +} + +static const struct class uverbs_class = { + .name = "infiniband_verbs", + .devnode = uverbs_devnode, +}; + /* * Must be called with the ufile->device->disassociate_srcu held, and the lock * must be held until use of the ucontext is finished. @@ -1117,7 +1128,7 @@ static int ib_uverbs_add_one(struct ib_device *device) } device_initialize(&uverbs_dev->dev); - uverbs_dev->dev.class = uverbs_class; + uverbs_dev->dev.class = &uverbs_class; uverbs_dev->dev.parent = device->dev.parent; uverbs_dev->dev.release = ib_uverbs_release_dev; uverbs_dev->groups[0] = &dev_attr_group; @@ -1235,13 +1246,6 @@ static void ib_uverbs_remove_one(struct ib_device *device, void *client_data) put_device(&uverbs_dev->dev); } -static char *uverbs_devnode(const struct device *dev, umode_t *mode) -{ - if (mode) - *mode = 0666; - return kasprintf(GFP_KERNEL, "infiniband/%s", dev_name(dev)); -} - static int __init ib_uverbs_init(void) { int ret; @@ -1262,16 +1266,13 @@ static int __init ib_uverbs_init(void) goto out_alloc; } - uverbs_class = class_create("infiniband_verbs"); - if (IS_ERR(uverbs_class)) { - ret = PTR_ERR(uverbs_class); + ret = class_register(&uverbs_class); + if (ret) { pr_err("user_verbs: couldn't create class infiniband_verbs\n"); goto out_chrdev; } - uverbs_class->devnode = uverbs_devnode; - - ret = class_create_file(uverbs_class, &class_attr_abi_version.attr); + ret = class_create_file(&uverbs_class, &class_attr_abi_version.attr); if (ret) { pr_err("user_verbs: couldn't create abi_version attribute\n"); goto out_class; @@ -1286,7 +1287,7 @@ static int __init ib_uverbs_init(void) return 0; out_class: - class_destroy(uverbs_class); + class_unregister(&uverbs_class); out_chrdev: unregister_chrdev_region(dynamic_uverbs_dev, @@ -1303,7 +1304,7 @@ out: static void __exit ib_uverbs_cleanup(void) { ib_unregister_client(&uverbs_client); - class_destroy(uverbs_class); + class_unregister(&uverbs_class); unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_NUM_FIXED_MINOR); unregister_chrdev_region(dynamic_uverbs_dev, diff --git a/drivers/infiniband/hw/hfi1/device.c b/drivers/infiniband/hw/hfi1/device.c index 05be0d119f796..b0a00b7aaec59 100644 --- a/drivers/infiniband/hw/hfi1/device.c +++ b/drivers/infiniband/hw/hfi1/device.c @@ -10,8 +10,29 @@ #include "hfi.h" #include "device.h" -static struct class *class; -static struct class *user_class; +static char *hfi1_devnode(const struct device *dev, umode_t *mode) +{ + if (mode) + *mode = 0600; + return kasprintf(GFP_KERNEL, "%s", dev_name(dev)); +} + +static const struct class class = { + .name = "hfi1", + .devnode = hfi1_devnode, +}; + +static char *hfi1_user_devnode(const struct device *dev, umode_t *mode) +{ + if (mode) + *mode = 0666; + return kasprintf(GFP_KERNEL, "%s", dev_name(dev)); +} + +static const struct class user_class = { + .name = "hfi1_user", + .devnode = hfi1_user_devnode, +}; static dev_t hfi1_dev; int hfi1_cdev_init(int minor, const char *name, @@ -37,9 +58,9 @@ int hfi1_cdev_init(int minor, const char *name, } if (user_accessible) - device = device_create(user_class, NULL, dev, NULL, "%s", name); + device = device_create(&user_class, NULL, dev, NULL, "%s", name); else - device = device_create(class, NULL, dev, NULL, "%s", name); + device = device_create(&class, NULL, dev, NULL, "%s", name); if (IS_ERR(device)) { ret = PTR_ERR(device); @@ -72,26 +93,6 @@ const char *class_name(void) return hfi1_class_name; } -static char *hfi1_devnode(const struct device *dev, umode_t *mode) -{ - if (mode) - *mode = 0600; - return kasprintf(GFP_KERNEL, "%s", dev_name(dev)); -} - -static const char *hfi1_class_name_user = "hfi1_user"; -static const char *class_name_user(void) -{ - return hfi1_class_name_user; -} - -static char *hfi1_user_devnode(const struct device *dev, umode_t *mode) -{ - if (mode) - *mode = 0666; - return kasprintf(GFP_KERNEL, "%s", dev_name(dev)); -} - int __init dev_init(void) { int ret; @@ -102,27 +103,21 @@ int __init dev_init(void) goto done; } - class = class_create(class_name()); - if (IS_ERR(class)) { - ret = PTR_ERR(class); + ret = class_register(&class); + if (ret) { pr_err("Could not create device class (err %d)\n", -ret); unregister_chrdev_region(hfi1_dev, HFI1_NMINORS); goto done; } - class->devnode = hfi1_devnode; - user_class = class_create(class_name_user()); - if (IS_ERR(user_class)) { - ret = PTR_ERR(user_class); + ret = class_register(&user_class); + if (ret) { pr_err("Could not create device class for user accessible files (err %d)\n", -ret); - class_destroy(class); - class = NULL; - user_class = NULL; + class_unregister(&class); unregister_chrdev_region(hfi1_dev, HFI1_NMINORS); goto done; } - user_class->devnode = hfi1_user_devnode; done: return ret; @@ -130,11 +125,8 @@ done: void dev_cleanup(void) { - class_destroy(class); - class = NULL; - - class_destroy(user_class); - user_class = NULL; + class_unregister(&class); + class_unregister(&user_class); unregister_chrdev_region(hfi1_dev, HFI1_NMINORS); } diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c index ef85bc8d9384c..152952127f131 100644 --- a/drivers/infiniband/hw/qib/qib_file_ops.c +++ b/drivers/infiniband/hw/qib/qib_file_ops.c @@ -2250,7 +2250,9 @@ static ssize_t qib_write_iter(struct kiocb *iocb, struct iov_iter *from) return qib_user_sdma_writev(rcd, pq, iter_iov(from), from->nr_segs); } -static struct class *qib_class; +static const struct class qib_class = { + .name = "ipath", +}; static dev_t qib_dev; int qib_cdev_init(int minor, const char *name, @@ -2281,7 +2283,7 @@ int qib_cdev_init(int minor, const char *name, goto err_cdev; } - device = device_create(qib_class, NULL, dev, NULL, "%s", name); + device = device_create(&qib_class, NULL, dev, NULL, "%s", name); if (!IS_ERR(device)) goto done; ret = PTR_ERR(device); @@ -2325,9 +2327,8 @@ int __init qib_dev_init(void) goto done; } - qib_class = class_create("ipath"); - if (IS_ERR(qib_class)) { - ret = PTR_ERR(qib_class); + ret = class_register(&qib_class); + if (ret) { pr_err("Could not create device class (err %d)\n", -ret); unregister_chrdev_region(qib_dev, QIB_NMINORS); } @@ -2338,10 +2339,8 @@ done: void qib_dev_cleanup(void) { - if (qib_class) { - class_destroy(qib_class); - qib_class = NULL; - } + if (class_is_registered(&qib_class)) + class_unregister(&qib_class); unregister_chrdev_region(qib_dev, QIB_NMINORS); } diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.c b/drivers/infiniband/ulp/rtrs/rtrs-clt.c index b32941dd67cb9..b6ee801fd0ffb 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-clt.c +++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.c @@ -45,7 +45,9 @@ static struct rtrs_rdma_dev_pd dev_pd = { }; static struct workqueue_struct *rtrs_wq; -static struct class *rtrs_clt_dev_class; +static const struct class rtrs_clt_dev_class = { + .name = "rtrs-client", +}; static inline bool rtrs_clt_is_connected(const struct rtrs_clt_sess *clt) { @@ -2698,7 +2700,7 @@ static struct rtrs_clt_sess *alloc_clt(const char *sessname, size_t paths_num, return ERR_PTR(-ENOMEM); } - clt->dev.class = rtrs_clt_dev_class; + clt->dev.class = &rtrs_clt_dev_class; clt->dev.release = rtrs_clt_dev_release; uuid_gen(&clt->paths_uuid); INIT_LIST_HEAD_RCU(&clt->paths_list); @@ -3151,16 +3153,17 @@ static const struct rtrs_rdma_dev_pd_ops dev_pd_ops = { static int __init rtrs_client_init(void) { - rtrs_rdma_dev_pd_init(0, &dev_pd); + int ret = 0; - rtrs_clt_dev_class = class_create("rtrs-client"); - if (IS_ERR(rtrs_clt_dev_class)) { + rtrs_rdma_dev_pd_init(0, &dev_pd); + ret = class_register(&rtrs_clt_dev_class); + if (ret) { pr_err("Failed to create rtrs-client dev class\n"); - return PTR_ERR(rtrs_clt_dev_class); + return ret; } rtrs_wq = alloc_workqueue("rtrs_client_wq", 0, 0); if (!rtrs_wq) { - class_destroy(rtrs_clt_dev_class); + class_unregister(&rtrs_clt_dev_class); return -ENOMEM; } @@ -3170,7 +3173,7 @@ static int __init rtrs_client_init(void) static void __exit rtrs_client_exit(void) { destroy_workqueue(rtrs_wq); - class_destroy(rtrs_clt_dev_class); + class_unregister(&rtrs_clt_dev_class); rtrs_rdma_dev_pd_deinit(&dev_pd); } diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv-sysfs.c b/drivers/infiniband/ulp/rtrs/rtrs-srv-sysfs.c index 5adba0f754b6b..3f305e694fe8c 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-srv-sysfs.c +++ b/drivers/infiniband/ulp/rtrs/rtrs-srv-sysfs.c @@ -164,7 +164,7 @@ static int rtrs_srv_create_once_sysfs_root_folders(struct rtrs_srv_path *srv_pat */ goto unlock; } - srv->dev.class = rtrs_dev_class; + srv->dev.class = &rtrs_dev_class; err = dev_set_name(&srv->dev, "%s", srv_path->s.sessname); if (err) goto unlock; diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c index c38901e2c8f42..75e56604e4628 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c +++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c @@ -27,7 +27,9 @@ MODULE_LICENSE("GPL"); #define MAX_HDR_SIZE PAGE_SIZE static struct rtrs_rdma_dev_pd dev_pd; -struct class *rtrs_dev_class; +const struct class rtrs_dev_class = { + .name = "rtrs-server", +}; static struct rtrs_srv_ib_ctx ib_ctx; static int __read_mostly max_chunk_size = DEFAULT_MAX_CHUNK_SIZE; @@ -2253,11 +2255,10 @@ static int __init rtrs_server_init(void) err); return err; } - rtrs_dev_class = class_create("rtrs-server"); - if (IS_ERR(rtrs_dev_class)) { - err = PTR_ERR(rtrs_dev_class); + err = class_register(&rtrs_dev_class); + if (err) goto out_err; - } + rtrs_wq = alloc_workqueue("rtrs_server_wq", 0, 0); if (!rtrs_wq) { err = -ENOMEM; @@ -2267,7 +2268,7 @@ static int __init rtrs_server_init(void) return 0; out_dev_class: - class_destroy(rtrs_dev_class); + class_unregister(&rtrs_dev_class); out_err: return err; } @@ -2275,7 +2276,7 @@ out_err: static void __exit rtrs_server_exit(void) { destroy_workqueue(rtrs_wq); - class_destroy(rtrs_dev_class); + class_unregister(&rtrs_dev_class); rtrs_rdma_dev_pd_deinit(&dev_pd); } diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.h b/drivers/infiniband/ulp/rtrs/rtrs-srv.h index 2f8a638e36fad..5e325b82ff336 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-srv.h +++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.h @@ -129,7 +129,7 @@ struct rtrs_srv_ib_ctx { int ib_dev_count; }; -extern struct class *rtrs_dev_class; +extern const struct class rtrs_dev_class; void close_path(struct rtrs_srv_path *srv_path); -- GitLab From e98b1085be795354073debd371e2889bea4902b9 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Tue, 11 Jul 2023 17:40:47 +0530 Subject: [PATCH 0904/3445] RISC-V: KVM: Factor-out ONE_REG related code to its own source file The VCPU ONE_REG interface has grown over time and it will continue to grow with new ISA extensions and other features. Let us move all ONE_REG related code to its own source file so that vcpu.c only focuses only on high-level VCPU functions. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- arch/riscv/include/asm/kvm_host.h | 6 + arch/riscv/kvm/Makefile | 1 + arch/riscv/kvm/vcpu.c | 529 +--------------------------- arch/riscv/kvm/vcpu_onereg.c | 548 ++++++++++++++++++++++++++++++ 4 files changed, 556 insertions(+), 528 deletions(-) create mode 100644 arch/riscv/kvm/vcpu_onereg.c diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h index 2d8ee53b66c7b..55bc7bdbff486 100644 --- a/arch/riscv/include/asm/kvm_host.h +++ b/arch/riscv/include/asm/kvm_host.h @@ -337,6 +337,12 @@ int kvm_riscv_vcpu_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, void __kvm_riscv_switch_to(struct kvm_vcpu_arch *vcpu_arch); +void kvm_riscv_vcpu_setup_isa(struct kvm_vcpu *vcpu); +int kvm_riscv_vcpu_get_reg(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg); +int kvm_riscv_vcpu_set_reg(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg); + int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq); int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq); void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu); diff --git a/arch/riscv/kvm/Makefile b/arch/riscv/kvm/Makefile index fee0671e2dc12..4c2067fc59fcb 100644 --- a/arch/riscv/kvm/Makefile +++ b/arch/riscv/kvm/Makefile @@ -19,6 +19,7 @@ kvm-y += vcpu_exit.o kvm-y += vcpu_fp.o kvm-y += vcpu_vector.o kvm-y += vcpu_insn.o +kvm-y += vcpu_onereg.o kvm-y += vcpu_switch.o kvm-y += vcpu_sbi.o kvm-$(CONFIG_RISCV_SBI_V01) += vcpu_sbi_v01.o diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c index d12ef99901fc5..452d6548e9512 100644 --- a/arch/riscv/kvm/vcpu.c +++ b/arch/riscv/kvm/vcpu.c @@ -13,16 +13,12 @@ #include #include #include -#include #include #include #include #include #include #include -#include -#include -#include #include const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { @@ -46,79 +42,6 @@ const struct kvm_stats_header kvm_vcpu_stats_header = { sizeof(kvm_vcpu_stats_desc), }; -#define KVM_RISCV_BASE_ISA_MASK GENMASK(25, 0) - -#define KVM_ISA_EXT_ARR(ext) [KVM_RISCV_ISA_EXT_##ext] = RISCV_ISA_EXT_##ext - -/* Mapping between KVM ISA Extension ID & Host ISA extension ID */ -static const unsigned long kvm_isa_ext_arr[] = { - [KVM_RISCV_ISA_EXT_A] = RISCV_ISA_EXT_a, - [KVM_RISCV_ISA_EXT_C] = RISCV_ISA_EXT_c, - [KVM_RISCV_ISA_EXT_D] = RISCV_ISA_EXT_d, - [KVM_RISCV_ISA_EXT_F] = RISCV_ISA_EXT_f, - [KVM_RISCV_ISA_EXT_H] = RISCV_ISA_EXT_h, - [KVM_RISCV_ISA_EXT_I] = RISCV_ISA_EXT_i, - [KVM_RISCV_ISA_EXT_M] = RISCV_ISA_EXT_m, - [KVM_RISCV_ISA_EXT_V] = RISCV_ISA_EXT_v, - - KVM_ISA_EXT_ARR(SSAIA), - KVM_ISA_EXT_ARR(SSTC), - KVM_ISA_EXT_ARR(SVINVAL), - KVM_ISA_EXT_ARR(SVNAPOT), - KVM_ISA_EXT_ARR(SVPBMT), - KVM_ISA_EXT_ARR(ZBB), - KVM_ISA_EXT_ARR(ZIHINTPAUSE), - KVM_ISA_EXT_ARR(ZICBOM), - KVM_ISA_EXT_ARR(ZICBOZ), -}; - -static unsigned long kvm_riscv_vcpu_base2isa_ext(unsigned long base_ext) -{ - unsigned long i; - - for (i = 0; i < KVM_RISCV_ISA_EXT_MAX; i++) { - if (kvm_isa_ext_arr[i] == base_ext) - return i; - } - - return KVM_RISCV_ISA_EXT_MAX; -} - -static bool kvm_riscv_vcpu_isa_enable_allowed(unsigned long ext) -{ - switch (ext) { - case KVM_RISCV_ISA_EXT_H: - return false; - case KVM_RISCV_ISA_EXT_V: - return riscv_v_vstate_ctrl_user_allowed(); - default: - break; - } - - return true; -} - -static bool kvm_riscv_vcpu_isa_disable_allowed(unsigned long ext) -{ - switch (ext) { - case KVM_RISCV_ISA_EXT_A: - case KVM_RISCV_ISA_EXT_C: - case KVM_RISCV_ISA_EXT_I: - case KVM_RISCV_ISA_EXT_M: - case KVM_RISCV_ISA_EXT_SSAIA: - case KVM_RISCV_ISA_EXT_SSTC: - case KVM_RISCV_ISA_EXT_SVINVAL: - case KVM_RISCV_ISA_EXT_SVNAPOT: - case KVM_RISCV_ISA_EXT_ZIHINTPAUSE: - case KVM_RISCV_ISA_EXT_ZBB: - return false; - default: - break; - } - - return true; -} - static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu) { struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; @@ -176,7 +99,6 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) int rc; struct kvm_cpu_context *cntx; struct kvm_vcpu_csr *reset_csr = &vcpu->arch.guest_reset_csr; - unsigned long host_isa, i; /* Mark this VCPU never ran */ vcpu->arch.ran_atleast_once = false; @@ -184,12 +106,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) bitmap_zero(vcpu->arch.isa, RISCV_ISA_EXT_MAX); /* Setup ISA features available to VCPU */ - for (i = 0; i < ARRAY_SIZE(kvm_isa_ext_arr); i++) { - host_isa = kvm_isa_ext_arr[i]; - if (__riscv_isa_extension_available(NULL, host_isa) && - kvm_riscv_vcpu_isa_enable_allowed(i)) - set_bit(host_isa, vcpu->arch.isa); - } + kvm_riscv_vcpu_setup_isa(vcpu); /* Setup vendor, arch, and implementation details */ vcpu->arch.mvendorid = sbi_get_mvendorid(); @@ -294,450 +211,6 @@ vm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf) return VM_FAULT_SIGBUS; } -static int kvm_riscv_vcpu_get_reg_config(struct kvm_vcpu *vcpu, - const struct kvm_one_reg *reg) -{ - unsigned long __user *uaddr = - (unsigned long __user *)(unsigned long)reg->addr; - unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | - KVM_REG_SIZE_MASK | - KVM_REG_RISCV_CONFIG); - unsigned long reg_val; - - if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) - return -EINVAL; - - switch (reg_num) { - case KVM_REG_RISCV_CONFIG_REG(isa): - reg_val = vcpu->arch.isa[0] & KVM_RISCV_BASE_ISA_MASK; - break; - case KVM_REG_RISCV_CONFIG_REG(zicbom_block_size): - if (!riscv_isa_extension_available(vcpu->arch.isa, ZICBOM)) - return -EINVAL; - reg_val = riscv_cbom_block_size; - break; - case KVM_REG_RISCV_CONFIG_REG(zicboz_block_size): - if (!riscv_isa_extension_available(vcpu->arch.isa, ZICBOZ)) - return -EINVAL; - reg_val = riscv_cboz_block_size; - break; - case KVM_REG_RISCV_CONFIG_REG(mvendorid): - reg_val = vcpu->arch.mvendorid; - break; - case KVM_REG_RISCV_CONFIG_REG(marchid): - reg_val = vcpu->arch.marchid; - break; - case KVM_REG_RISCV_CONFIG_REG(mimpid): - reg_val = vcpu->arch.mimpid; - break; - default: - return -EINVAL; - } - - if (copy_to_user(uaddr, ®_val, KVM_REG_SIZE(reg->id))) - return -EFAULT; - - return 0; -} - -static int kvm_riscv_vcpu_set_reg_config(struct kvm_vcpu *vcpu, - const struct kvm_one_reg *reg) -{ - unsigned long __user *uaddr = - (unsigned long __user *)(unsigned long)reg->addr; - unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | - KVM_REG_SIZE_MASK | - KVM_REG_RISCV_CONFIG); - unsigned long i, isa_ext, reg_val; - - if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) - return -EINVAL; - - if (copy_from_user(®_val, uaddr, KVM_REG_SIZE(reg->id))) - return -EFAULT; - - switch (reg_num) { - case KVM_REG_RISCV_CONFIG_REG(isa): - /* - * This ONE REG interface is only defined for - * single letter extensions. - */ - if (fls(reg_val) >= RISCV_ISA_EXT_BASE) - return -EINVAL; - - if (!vcpu->arch.ran_atleast_once) { - /* Ignore the enable/disable request for certain extensions */ - for (i = 0; i < RISCV_ISA_EXT_BASE; i++) { - isa_ext = kvm_riscv_vcpu_base2isa_ext(i); - if (isa_ext >= KVM_RISCV_ISA_EXT_MAX) { - reg_val &= ~BIT(i); - continue; - } - if (!kvm_riscv_vcpu_isa_enable_allowed(isa_ext)) - if (reg_val & BIT(i)) - reg_val &= ~BIT(i); - if (!kvm_riscv_vcpu_isa_disable_allowed(isa_ext)) - if (!(reg_val & BIT(i))) - reg_val |= BIT(i); - } - reg_val &= riscv_isa_extension_base(NULL); - /* Do not modify anything beyond single letter extensions */ - reg_val = (vcpu->arch.isa[0] & ~KVM_RISCV_BASE_ISA_MASK) | - (reg_val & KVM_RISCV_BASE_ISA_MASK); - vcpu->arch.isa[0] = reg_val; - kvm_riscv_vcpu_fp_reset(vcpu); - } else { - return -EOPNOTSUPP; - } - break; - case KVM_REG_RISCV_CONFIG_REG(zicbom_block_size): - return -EOPNOTSUPP; - case KVM_REG_RISCV_CONFIG_REG(zicboz_block_size): - return -EOPNOTSUPP; - case KVM_REG_RISCV_CONFIG_REG(mvendorid): - if (!vcpu->arch.ran_atleast_once) - vcpu->arch.mvendorid = reg_val; - else - return -EBUSY; - break; - case KVM_REG_RISCV_CONFIG_REG(marchid): - if (!vcpu->arch.ran_atleast_once) - vcpu->arch.marchid = reg_val; - else - return -EBUSY; - break; - case KVM_REG_RISCV_CONFIG_REG(mimpid): - if (!vcpu->arch.ran_atleast_once) - vcpu->arch.mimpid = reg_val; - else - return -EBUSY; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int kvm_riscv_vcpu_get_reg_core(struct kvm_vcpu *vcpu, - const struct kvm_one_reg *reg) -{ - struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; - unsigned long __user *uaddr = - (unsigned long __user *)(unsigned long)reg->addr; - unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | - KVM_REG_SIZE_MASK | - KVM_REG_RISCV_CORE); - unsigned long reg_val; - - if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) - return -EINVAL; - if (reg_num >= sizeof(struct kvm_riscv_core) / sizeof(unsigned long)) - return -EINVAL; - - if (reg_num == KVM_REG_RISCV_CORE_REG(regs.pc)) - reg_val = cntx->sepc; - else if (KVM_REG_RISCV_CORE_REG(regs.pc) < reg_num && - reg_num <= KVM_REG_RISCV_CORE_REG(regs.t6)) - reg_val = ((unsigned long *)cntx)[reg_num]; - else if (reg_num == KVM_REG_RISCV_CORE_REG(mode)) - reg_val = (cntx->sstatus & SR_SPP) ? - KVM_RISCV_MODE_S : KVM_RISCV_MODE_U; - else - return -EINVAL; - - if (copy_to_user(uaddr, ®_val, KVM_REG_SIZE(reg->id))) - return -EFAULT; - - return 0; -} - -static int kvm_riscv_vcpu_set_reg_core(struct kvm_vcpu *vcpu, - const struct kvm_one_reg *reg) -{ - struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; - unsigned long __user *uaddr = - (unsigned long __user *)(unsigned long)reg->addr; - unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | - KVM_REG_SIZE_MASK | - KVM_REG_RISCV_CORE); - unsigned long reg_val; - - if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) - return -EINVAL; - if (reg_num >= sizeof(struct kvm_riscv_core) / sizeof(unsigned long)) - return -EINVAL; - - if (copy_from_user(®_val, uaddr, KVM_REG_SIZE(reg->id))) - return -EFAULT; - - if (reg_num == KVM_REG_RISCV_CORE_REG(regs.pc)) - cntx->sepc = reg_val; - else if (KVM_REG_RISCV_CORE_REG(regs.pc) < reg_num && - reg_num <= KVM_REG_RISCV_CORE_REG(regs.t6)) - ((unsigned long *)cntx)[reg_num] = reg_val; - else if (reg_num == KVM_REG_RISCV_CORE_REG(mode)) { - if (reg_val == KVM_RISCV_MODE_S) - cntx->sstatus |= SR_SPP; - else - cntx->sstatus &= ~SR_SPP; - } else - return -EINVAL; - - return 0; -} - -static int kvm_riscv_vcpu_general_get_csr(struct kvm_vcpu *vcpu, - unsigned long reg_num, - unsigned long *out_val) -{ - struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; - - if (reg_num >= sizeof(struct kvm_riscv_csr) / sizeof(unsigned long)) - return -EINVAL; - - if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) { - kvm_riscv_vcpu_flush_interrupts(vcpu); - *out_val = (csr->hvip >> VSIP_TO_HVIP_SHIFT) & VSIP_VALID_MASK; - *out_val |= csr->hvip & ~IRQ_LOCAL_MASK; - } else - *out_val = ((unsigned long *)csr)[reg_num]; - - return 0; -} - -static inline int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu, - unsigned long reg_num, - unsigned long reg_val) -{ - struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; - - if (reg_num >= sizeof(struct kvm_riscv_csr) / sizeof(unsigned long)) - return -EINVAL; - - if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) { - reg_val &= VSIP_VALID_MASK; - reg_val <<= VSIP_TO_HVIP_SHIFT; - } - - ((unsigned long *)csr)[reg_num] = reg_val; - - if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) - WRITE_ONCE(vcpu->arch.irqs_pending_mask[0], 0); - - return 0; -} - -static int kvm_riscv_vcpu_get_reg_csr(struct kvm_vcpu *vcpu, - const struct kvm_one_reg *reg) -{ - int rc; - unsigned long __user *uaddr = - (unsigned long __user *)(unsigned long)reg->addr; - unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | - KVM_REG_SIZE_MASK | - KVM_REG_RISCV_CSR); - unsigned long reg_val, reg_subtype; - - if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) - return -EINVAL; - - reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK; - reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK; - switch (reg_subtype) { - case KVM_REG_RISCV_CSR_GENERAL: - rc = kvm_riscv_vcpu_general_get_csr(vcpu, reg_num, ®_val); - break; - case KVM_REG_RISCV_CSR_AIA: - rc = kvm_riscv_vcpu_aia_get_csr(vcpu, reg_num, ®_val); - break; - default: - rc = -EINVAL; - break; - } - if (rc) - return rc; - - if (copy_to_user(uaddr, ®_val, KVM_REG_SIZE(reg->id))) - return -EFAULT; - - return 0; -} - -static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu, - const struct kvm_one_reg *reg) -{ - int rc; - unsigned long __user *uaddr = - (unsigned long __user *)(unsigned long)reg->addr; - unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | - KVM_REG_SIZE_MASK | - KVM_REG_RISCV_CSR); - unsigned long reg_val, reg_subtype; - - if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) - return -EINVAL; - - if (copy_from_user(®_val, uaddr, KVM_REG_SIZE(reg->id))) - return -EFAULT; - - reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK; - reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK; - switch (reg_subtype) { - case KVM_REG_RISCV_CSR_GENERAL: - rc = kvm_riscv_vcpu_general_set_csr(vcpu, reg_num, reg_val); - break; - case KVM_REG_RISCV_CSR_AIA: - rc = kvm_riscv_vcpu_aia_set_csr(vcpu, reg_num, reg_val); - break; - default: - rc = -EINVAL; - break; - } - if (rc) - return rc; - - return 0; -} - -static int kvm_riscv_vcpu_get_reg_isa_ext(struct kvm_vcpu *vcpu, - const struct kvm_one_reg *reg) -{ - unsigned long __user *uaddr = - (unsigned long __user *)(unsigned long)reg->addr; - unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | - KVM_REG_SIZE_MASK | - KVM_REG_RISCV_ISA_EXT); - unsigned long reg_val = 0; - unsigned long host_isa_ext; - - if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) - return -EINVAL; - - if (reg_num >= KVM_RISCV_ISA_EXT_MAX || - reg_num >= ARRAY_SIZE(kvm_isa_ext_arr)) - return -EINVAL; - - host_isa_ext = kvm_isa_ext_arr[reg_num]; - if (__riscv_isa_extension_available(vcpu->arch.isa, host_isa_ext)) - reg_val = 1; /* Mark the given extension as available */ - - if (copy_to_user(uaddr, ®_val, KVM_REG_SIZE(reg->id))) - return -EFAULT; - - return 0; -} - -static int kvm_riscv_vcpu_set_reg_isa_ext(struct kvm_vcpu *vcpu, - const struct kvm_one_reg *reg) -{ - unsigned long __user *uaddr = - (unsigned long __user *)(unsigned long)reg->addr; - unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | - KVM_REG_SIZE_MASK | - KVM_REG_RISCV_ISA_EXT); - unsigned long reg_val; - unsigned long host_isa_ext; - - if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) - return -EINVAL; - - if (reg_num >= KVM_RISCV_ISA_EXT_MAX || - reg_num >= ARRAY_SIZE(kvm_isa_ext_arr)) - return -EINVAL; - - if (copy_from_user(®_val, uaddr, KVM_REG_SIZE(reg->id))) - return -EFAULT; - - host_isa_ext = kvm_isa_ext_arr[reg_num]; - if (!__riscv_isa_extension_available(NULL, host_isa_ext)) - return -EOPNOTSUPP; - - if (!vcpu->arch.ran_atleast_once) { - /* - * All multi-letter extension and a few single letter - * extension can be disabled - */ - if (reg_val == 1 && - kvm_riscv_vcpu_isa_enable_allowed(reg_num)) - set_bit(host_isa_ext, vcpu->arch.isa); - else if (!reg_val && - kvm_riscv_vcpu_isa_disable_allowed(reg_num)) - clear_bit(host_isa_ext, vcpu->arch.isa); - else - return -EINVAL; - kvm_riscv_vcpu_fp_reset(vcpu); - } else { - return -EOPNOTSUPP; - } - - return 0; -} - -static int kvm_riscv_vcpu_set_reg(struct kvm_vcpu *vcpu, - const struct kvm_one_reg *reg) -{ - switch (reg->id & KVM_REG_RISCV_TYPE_MASK) { - case KVM_REG_RISCV_CONFIG: - return kvm_riscv_vcpu_set_reg_config(vcpu, reg); - case KVM_REG_RISCV_CORE: - return kvm_riscv_vcpu_set_reg_core(vcpu, reg); - case KVM_REG_RISCV_CSR: - return kvm_riscv_vcpu_set_reg_csr(vcpu, reg); - case KVM_REG_RISCV_TIMER: - return kvm_riscv_vcpu_set_reg_timer(vcpu, reg); - case KVM_REG_RISCV_FP_F: - return kvm_riscv_vcpu_set_reg_fp(vcpu, reg, - KVM_REG_RISCV_FP_F); - case KVM_REG_RISCV_FP_D: - return kvm_riscv_vcpu_set_reg_fp(vcpu, reg, - KVM_REG_RISCV_FP_D); - case KVM_REG_RISCV_ISA_EXT: - return kvm_riscv_vcpu_set_reg_isa_ext(vcpu, reg); - case KVM_REG_RISCV_SBI_EXT: - return kvm_riscv_vcpu_set_reg_sbi_ext(vcpu, reg); - case KVM_REG_RISCV_VECTOR: - return kvm_riscv_vcpu_set_reg_vector(vcpu, reg, - KVM_REG_RISCV_VECTOR); - default: - break; - } - - return -EINVAL; -} - -static int kvm_riscv_vcpu_get_reg(struct kvm_vcpu *vcpu, - const struct kvm_one_reg *reg) -{ - switch (reg->id & KVM_REG_RISCV_TYPE_MASK) { - case KVM_REG_RISCV_CONFIG: - return kvm_riscv_vcpu_get_reg_config(vcpu, reg); - case KVM_REG_RISCV_CORE: - return kvm_riscv_vcpu_get_reg_core(vcpu, reg); - case KVM_REG_RISCV_CSR: - return kvm_riscv_vcpu_get_reg_csr(vcpu, reg); - case KVM_REG_RISCV_TIMER: - return kvm_riscv_vcpu_get_reg_timer(vcpu, reg); - case KVM_REG_RISCV_FP_F: - return kvm_riscv_vcpu_get_reg_fp(vcpu, reg, - KVM_REG_RISCV_FP_F); - case KVM_REG_RISCV_FP_D: - return kvm_riscv_vcpu_get_reg_fp(vcpu, reg, - KVM_REG_RISCV_FP_D); - case KVM_REG_RISCV_ISA_EXT: - return kvm_riscv_vcpu_get_reg_isa_ext(vcpu, reg); - case KVM_REG_RISCV_SBI_EXT: - return kvm_riscv_vcpu_get_reg_sbi_ext(vcpu, reg); - case KVM_REG_RISCV_VECTOR: - return kvm_riscv_vcpu_get_reg_vector(vcpu, reg, - KVM_REG_RISCV_VECTOR); - default: - break; - } - - return -EINVAL; -} - long kvm_arch_vcpu_async_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c new file mode 100644 index 0000000000000..3efa2a77d2d95 --- /dev/null +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -0,0 +1,548 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Western Digital Corporation or its affiliates. + * Copyright (C) 2023 Ventana Micro Systems Inc. + * + * Authors: + * Anup Patel + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define KVM_RISCV_BASE_ISA_MASK GENMASK(25, 0) + +#define KVM_ISA_EXT_ARR(ext) \ +[KVM_RISCV_ISA_EXT_##ext] = RISCV_ISA_EXT_##ext + +/* Mapping between KVM ISA Extension ID & Host ISA extension ID */ +static const unsigned long kvm_isa_ext_arr[] = { + [KVM_RISCV_ISA_EXT_A] = RISCV_ISA_EXT_a, + [KVM_RISCV_ISA_EXT_C] = RISCV_ISA_EXT_c, + [KVM_RISCV_ISA_EXT_D] = RISCV_ISA_EXT_d, + [KVM_RISCV_ISA_EXT_F] = RISCV_ISA_EXT_f, + [KVM_RISCV_ISA_EXT_H] = RISCV_ISA_EXT_h, + [KVM_RISCV_ISA_EXT_I] = RISCV_ISA_EXT_i, + [KVM_RISCV_ISA_EXT_M] = RISCV_ISA_EXT_m, + [KVM_RISCV_ISA_EXT_V] = RISCV_ISA_EXT_v, + + KVM_ISA_EXT_ARR(SSAIA), + KVM_ISA_EXT_ARR(SSTC), + KVM_ISA_EXT_ARR(SVINVAL), + KVM_ISA_EXT_ARR(SVNAPOT), + KVM_ISA_EXT_ARR(SVPBMT), + KVM_ISA_EXT_ARR(ZBB), + KVM_ISA_EXT_ARR(ZIHINTPAUSE), + KVM_ISA_EXT_ARR(ZICBOM), + KVM_ISA_EXT_ARR(ZICBOZ), +}; + +static unsigned long kvm_riscv_vcpu_base2isa_ext(unsigned long base_ext) +{ + unsigned long i; + + for (i = 0; i < KVM_RISCV_ISA_EXT_MAX; i++) { + if (kvm_isa_ext_arr[i] == base_ext) + return i; + } + + return KVM_RISCV_ISA_EXT_MAX; +} + +static bool kvm_riscv_vcpu_isa_enable_allowed(unsigned long ext) +{ + switch (ext) { + case KVM_RISCV_ISA_EXT_H: + return false; + case KVM_RISCV_ISA_EXT_V: + return riscv_v_vstate_ctrl_user_allowed(); + default: + break; + } + + return true; +} + +static bool kvm_riscv_vcpu_isa_disable_allowed(unsigned long ext) +{ + switch (ext) { + case KVM_RISCV_ISA_EXT_A: + case KVM_RISCV_ISA_EXT_C: + case KVM_RISCV_ISA_EXT_I: + case KVM_RISCV_ISA_EXT_M: + case KVM_RISCV_ISA_EXT_SSAIA: + case KVM_RISCV_ISA_EXT_SSTC: + case KVM_RISCV_ISA_EXT_SVINVAL: + case KVM_RISCV_ISA_EXT_SVNAPOT: + case KVM_RISCV_ISA_EXT_ZIHINTPAUSE: + case KVM_RISCV_ISA_EXT_ZBB: + return false; + default: + break; + } + + return true; +} + +void kvm_riscv_vcpu_setup_isa(struct kvm_vcpu *vcpu) +{ + unsigned long host_isa, i; + + for (i = 0; i < ARRAY_SIZE(kvm_isa_ext_arr); i++) { + host_isa = kvm_isa_ext_arr[i]; + if (__riscv_isa_extension_available(NULL, host_isa) && + kvm_riscv_vcpu_isa_enable_allowed(i)) + set_bit(host_isa, vcpu->arch.isa); + } +} + +static int kvm_riscv_vcpu_get_reg_config(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg) +{ + unsigned long __user *uaddr = + (unsigned long __user *)(unsigned long)reg->addr; + unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | + KVM_REG_SIZE_MASK | + KVM_REG_RISCV_CONFIG); + unsigned long reg_val; + + if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) + return -EINVAL; + + switch (reg_num) { + case KVM_REG_RISCV_CONFIG_REG(isa): + reg_val = vcpu->arch.isa[0] & KVM_RISCV_BASE_ISA_MASK; + break; + case KVM_REG_RISCV_CONFIG_REG(zicbom_block_size): + if (!riscv_isa_extension_available(vcpu->arch.isa, ZICBOM)) + return -EINVAL; + reg_val = riscv_cbom_block_size; + break; + case KVM_REG_RISCV_CONFIG_REG(zicboz_block_size): + if (!riscv_isa_extension_available(vcpu->arch.isa, ZICBOZ)) + return -EINVAL; + reg_val = riscv_cboz_block_size; + break; + case KVM_REG_RISCV_CONFIG_REG(mvendorid): + reg_val = vcpu->arch.mvendorid; + break; + case KVM_REG_RISCV_CONFIG_REG(marchid): + reg_val = vcpu->arch.marchid; + break; + case KVM_REG_RISCV_CONFIG_REG(mimpid): + reg_val = vcpu->arch.mimpid; + break; + default: + return -EINVAL; + } + + if (copy_to_user(uaddr, ®_val, KVM_REG_SIZE(reg->id))) + return -EFAULT; + + return 0; +} + +static int kvm_riscv_vcpu_set_reg_config(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg) +{ + unsigned long __user *uaddr = + (unsigned long __user *)(unsigned long)reg->addr; + unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | + KVM_REG_SIZE_MASK | + KVM_REG_RISCV_CONFIG); + unsigned long i, isa_ext, reg_val; + + if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) + return -EINVAL; + + if (copy_from_user(®_val, uaddr, KVM_REG_SIZE(reg->id))) + return -EFAULT; + + switch (reg_num) { + case KVM_REG_RISCV_CONFIG_REG(isa): + /* + * This ONE REG interface is only defined for + * single letter extensions. + */ + if (fls(reg_val) >= RISCV_ISA_EXT_BASE) + return -EINVAL; + + if (!vcpu->arch.ran_atleast_once) { + /* Ignore the enable/disable request for certain extensions */ + for (i = 0; i < RISCV_ISA_EXT_BASE; i++) { + isa_ext = kvm_riscv_vcpu_base2isa_ext(i); + if (isa_ext >= KVM_RISCV_ISA_EXT_MAX) { + reg_val &= ~BIT(i); + continue; + } + if (!kvm_riscv_vcpu_isa_enable_allowed(isa_ext)) + if (reg_val & BIT(i)) + reg_val &= ~BIT(i); + if (!kvm_riscv_vcpu_isa_disable_allowed(isa_ext)) + if (!(reg_val & BIT(i))) + reg_val |= BIT(i); + } + reg_val &= riscv_isa_extension_base(NULL); + /* Do not modify anything beyond single letter extensions */ + reg_val = (vcpu->arch.isa[0] & ~KVM_RISCV_BASE_ISA_MASK) | + (reg_val & KVM_RISCV_BASE_ISA_MASK); + vcpu->arch.isa[0] = reg_val; + kvm_riscv_vcpu_fp_reset(vcpu); + } else { + return -EOPNOTSUPP; + } + break; + case KVM_REG_RISCV_CONFIG_REG(zicbom_block_size): + return -EOPNOTSUPP; + case KVM_REG_RISCV_CONFIG_REG(zicboz_block_size): + return -EOPNOTSUPP; + case KVM_REG_RISCV_CONFIG_REG(mvendorid): + if (!vcpu->arch.ran_atleast_once) + vcpu->arch.mvendorid = reg_val; + else + return -EBUSY; + break; + case KVM_REG_RISCV_CONFIG_REG(marchid): + if (!vcpu->arch.ran_atleast_once) + vcpu->arch.marchid = reg_val; + else + return -EBUSY; + break; + case KVM_REG_RISCV_CONFIG_REG(mimpid): + if (!vcpu->arch.ran_atleast_once) + vcpu->arch.mimpid = reg_val; + else + return -EBUSY; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int kvm_riscv_vcpu_get_reg_core(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg) +{ + struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; + unsigned long __user *uaddr = + (unsigned long __user *)(unsigned long)reg->addr; + unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | + KVM_REG_SIZE_MASK | + KVM_REG_RISCV_CORE); + unsigned long reg_val; + + if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) + return -EINVAL; + if (reg_num >= sizeof(struct kvm_riscv_core) / sizeof(unsigned long)) + return -EINVAL; + + if (reg_num == KVM_REG_RISCV_CORE_REG(regs.pc)) + reg_val = cntx->sepc; + else if (KVM_REG_RISCV_CORE_REG(regs.pc) < reg_num && + reg_num <= KVM_REG_RISCV_CORE_REG(regs.t6)) + reg_val = ((unsigned long *)cntx)[reg_num]; + else if (reg_num == KVM_REG_RISCV_CORE_REG(mode)) + reg_val = (cntx->sstatus & SR_SPP) ? + KVM_RISCV_MODE_S : KVM_RISCV_MODE_U; + else + return -EINVAL; + + if (copy_to_user(uaddr, ®_val, KVM_REG_SIZE(reg->id))) + return -EFAULT; + + return 0; +} + +static int kvm_riscv_vcpu_set_reg_core(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg) +{ + struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; + unsigned long __user *uaddr = + (unsigned long __user *)(unsigned long)reg->addr; + unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | + KVM_REG_SIZE_MASK | + KVM_REG_RISCV_CORE); + unsigned long reg_val; + + if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) + return -EINVAL; + if (reg_num >= sizeof(struct kvm_riscv_core) / sizeof(unsigned long)) + return -EINVAL; + + if (copy_from_user(®_val, uaddr, KVM_REG_SIZE(reg->id))) + return -EFAULT; + + if (reg_num == KVM_REG_RISCV_CORE_REG(regs.pc)) + cntx->sepc = reg_val; + else if (KVM_REG_RISCV_CORE_REG(regs.pc) < reg_num && + reg_num <= KVM_REG_RISCV_CORE_REG(regs.t6)) + ((unsigned long *)cntx)[reg_num] = reg_val; + else if (reg_num == KVM_REG_RISCV_CORE_REG(mode)) { + if (reg_val == KVM_RISCV_MODE_S) + cntx->sstatus |= SR_SPP; + else + cntx->sstatus &= ~SR_SPP; + } else + return -EINVAL; + + return 0; +} + +static int kvm_riscv_vcpu_general_get_csr(struct kvm_vcpu *vcpu, + unsigned long reg_num, + unsigned long *out_val) +{ + struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; + + if (reg_num >= sizeof(struct kvm_riscv_csr) / sizeof(unsigned long)) + return -EINVAL; + + if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) { + kvm_riscv_vcpu_flush_interrupts(vcpu); + *out_val = (csr->hvip >> VSIP_TO_HVIP_SHIFT) & VSIP_VALID_MASK; + *out_val |= csr->hvip & ~IRQ_LOCAL_MASK; + } else + *out_val = ((unsigned long *)csr)[reg_num]; + + return 0; +} + +static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu, + unsigned long reg_num, + unsigned long reg_val) +{ + struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; + + if (reg_num >= sizeof(struct kvm_riscv_csr) / sizeof(unsigned long)) + return -EINVAL; + + if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) { + reg_val &= VSIP_VALID_MASK; + reg_val <<= VSIP_TO_HVIP_SHIFT; + } + + ((unsigned long *)csr)[reg_num] = reg_val; + + if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) + WRITE_ONCE(vcpu->arch.irqs_pending_mask[0], 0); + + return 0; +} + +static int kvm_riscv_vcpu_get_reg_csr(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg) +{ + int rc; + unsigned long __user *uaddr = + (unsigned long __user *)(unsigned long)reg->addr; + unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | + KVM_REG_SIZE_MASK | + KVM_REG_RISCV_CSR); + unsigned long reg_val, reg_subtype; + + if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) + return -EINVAL; + + reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK; + reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK; + switch (reg_subtype) { + case KVM_REG_RISCV_CSR_GENERAL: + rc = kvm_riscv_vcpu_general_get_csr(vcpu, reg_num, ®_val); + break; + case KVM_REG_RISCV_CSR_AIA: + rc = kvm_riscv_vcpu_aia_get_csr(vcpu, reg_num, ®_val); + break; + default: + rc = -EINVAL; + break; + } + if (rc) + return rc; + + if (copy_to_user(uaddr, ®_val, KVM_REG_SIZE(reg->id))) + return -EFAULT; + + return 0; +} + +static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg) +{ + int rc; + unsigned long __user *uaddr = + (unsigned long __user *)(unsigned long)reg->addr; + unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | + KVM_REG_SIZE_MASK | + KVM_REG_RISCV_CSR); + unsigned long reg_val, reg_subtype; + + if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) + return -EINVAL; + + if (copy_from_user(®_val, uaddr, KVM_REG_SIZE(reg->id))) + return -EFAULT; + + reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK; + reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK; + switch (reg_subtype) { + case KVM_REG_RISCV_CSR_GENERAL: + rc = kvm_riscv_vcpu_general_set_csr(vcpu, reg_num, reg_val); + break; + case KVM_REG_RISCV_CSR_AIA: + rc = kvm_riscv_vcpu_aia_set_csr(vcpu, reg_num, reg_val); + break; + default: + rc = -EINVAL; + break; + } + if (rc) + return rc; + + return 0; +} + +static int kvm_riscv_vcpu_get_reg_isa_ext(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg) +{ + unsigned long __user *uaddr = + (unsigned long __user *)(unsigned long)reg->addr; + unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | + KVM_REG_SIZE_MASK | + KVM_REG_RISCV_ISA_EXT); + unsigned long reg_val = 0; + unsigned long host_isa_ext; + + if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) + return -EINVAL; + + if (reg_num >= KVM_RISCV_ISA_EXT_MAX || + reg_num >= ARRAY_SIZE(kvm_isa_ext_arr)) + return -EINVAL; + + host_isa_ext = kvm_isa_ext_arr[reg_num]; + if (__riscv_isa_extension_available(vcpu->arch.isa, host_isa_ext)) + reg_val = 1; /* Mark the given extension as available */ + + if (copy_to_user(uaddr, ®_val, KVM_REG_SIZE(reg->id))) + return -EFAULT; + + return 0; +} + +static int kvm_riscv_vcpu_set_reg_isa_ext(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg) +{ + unsigned long __user *uaddr = + (unsigned long __user *)(unsigned long)reg->addr; + unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | + KVM_REG_SIZE_MASK | + KVM_REG_RISCV_ISA_EXT); + unsigned long reg_val; + unsigned long host_isa_ext; + + if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) + return -EINVAL; + + if (reg_num >= KVM_RISCV_ISA_EXT_MAX || + reg_num >= ARRAY_SIZE(kvm_isa_ext_arr)) + return -EINVAL; + + if (copy_from_user(®_val, uaddr, KVM_REG_SIZE(reg->id))) + return -EFAULT; + + host_isa_ext = kvm_isa_ext_arr[reg_num]; + if (!__riscv_isa_extension_available(NULL, host_isa_ext)) + return -EOPNOTSUPP; + + if (!vcpu->arch.ran_atleast_once) { + /* + * All multi-letter extension and a few single letter + * extension can be disabled + */ + if (reg_val == 1 && + kvm_riscv_vcpu_isa_enable_allowed(reg_num)) + set_bit(host_isa_ext, vcpu->arch.isa); + else if (!reg_val && + kvm_riscv_vcpu_isa_disable_allowed(reg_num)) + clear_bit(host_isa_ext, vcpu->arch.isa); + else + return -EINVAL; + kvm_riscv_vcpu_fp_reset(vcpu); + } else { + return -EOPNOTSUPP; + } + + return 0; +} + +int kvm_riscv_vcpu_set_reg(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg) +{ + switch (reg->id & KVM_REG_RISCV_TYPE_MASK) { + case KVM_REG_RISCV_CONFIG: + return kvm_riscv_vcpu_set_reg_config(vcpu, reg); + case KVM_REG_RISCV_CORE: + return kvm_riscv_vcpu_set_reg_core(vcpu, reg); + case KVM_REG_RISCV_CSR: + return kvm_riscv_vcpu_set_reg_csr(vcpu, reg); + case KVM_REG_RISCV_TIMER: + return kvm_riscv_vcpu_set_reg_timer(vcpu, reg); + case KVM_REG_RISCV_FP_F: + return kvm_riscv_vcpu_set_reg_fp(vcpu, reg, + KVM_REG_RISCV_FP_F); + case KVM_REG_RISCV_FP_D: + return kvm_riscv_vcpu_set_reg_fp(vcpu, reg, + KVM_REG_RISCV_FP_D); + case KVM_REG_RISCV_ISA_EXT: + return kvm_riscv_vcpu_set_reg_isa_ext(vcpu, reg); + case KVM_REG_RISCV_SBI_EXT: + return kvm_riscv_vcpu_set_reg_sbi_ext(vcpu, reg); + case KVM_REG_RISCV_VECTOR: + return kvm_riscv_vcpu_set_reg_vector(vcpu, reg, + KVM_REG_RISCV_VECTOR); + default: + break; + } + + return -EINVAL; +} + +int kvm_riscv_vcpu_get_reg(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg) +{ + switch (reg->id & KVM_REG_RISCV_TYPE_MASK) { + case KVM_REG_RISCV_CONFIG: + return kvm_riscv_vcpu_get_reg_config(vcpu, reg); + case KVM_REG_RISCV_CORE: + return kvm_riscv_vcpu_get_reg_core(vcpu, reg); + case KVM_REG_RISCV_CSR: + return kvm_riscv_vcpu_get_reg_csr(vcpu, reg); + case KVM_REG_RISCV_TIMER: + return kvm_riscv_vcpu_get_reg_timer(vcpu, reg); + case KVM_REG_RISCV_FP_F: + return kvm_riscv_vcpu_get_reg_fp(vcpu, reg, + KVM_REG_RISCV_FP_F); + case KVM_REG_RISCV_FP_D: + return kvm_riscv_vcpu_get_reg_fp(vcpu, reg, + KVM_REG_RISCV_FP_D); + case KVM_REG_RISCV_ISA_EXT: + return kvm_riscv_vcpu_get_reg_isa_ext(vcpu, reg); + case KVM_REG_RISCV_SBI_EXT: + return kvm_riscv_vcpu_get_reg_sbi_ext(vcpu, reg); + case KVM_REG_RISCV_VECTOR: + return kvm_riscv_vcpu_get_reg_vector(vcpu, reg, + KVM_REG_RISCV_VECTOR); + default: + break; + } + + return -EINVAL; +} -- GitLab From 613029442a4b837d3f8ce8ab08064f095ecdbdb6 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Tue, 11 Jul 2023 22:11:16 +0530 Subject: [PATCH 0905/3445] RISC-V: KVM: Extend ONE_REG to enable/disable multiple ISA extensions Currently, the ISA extension ONE_REG interface only allows enabling or disabling one extension at a time. To improve this, we extend the ISA extension ONE_REG interface (similar to SBI extension ONE_REG interface) so that KVM user space can enable/disable multiple extensions in one ioctl. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- arch/riscv/include/uapi/asm/kvm.h | 9 ++ arch/riscv/kvm/vcpu_onereg.c | 153 ++++++++++++++++++++++++------ 2 files changed, 133 insertions(+), 29 deletions(-) diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h index 930fdc4101cda..6c2285f865452 100644 --- a/arch/riscv/include/uapi/asm/kvm.h +++ b/arch/riscv/include/uapi/asm/kvm.h @@ -193,6 +193,15 @@ enum KVM_RISCV_SBI_EXT_ID { /* ISA Extension registers are mapped as type 7 */ #define KVM_REG_RISCV_ISA_EXT (0x07 << KVM_REG_RISCV_TYPE_SHIFT) +#define KVM_REG_RISCV_ISA_SINGLE (0x0 << KVM_REG_RISCV_SUBTYPE_SHIFT) +#define KVM_REG_RISCV_ISA_MULTI_EN (0x1 << KVM_REG_RISCV_SUBTYPE_SHIFT) +#define KVM_REG_RISCV_ISA_MULTI_DIS (0x2 << KVM_REG_RISCV_SUBTYPE_SHIFT) +#define KVM_REG_RISCV_ISA_MULTI_REG(__ext_id) \ + ((__ext_id) / __BITS_PER_LONG) +#define KVM_REG_RISCV_ISA_MULTI_MASK(__ext_id) \ + (1UL << ((__ext_id) % __BITS_PER_LONG)) +#define KVM_REG_RISCV_ISA_MULTI_REG_LAST \ + KVM_REG_RISCV_ISA_MULTI_REG(KVM_RISCV_ISA_EXT_MAX - 1) /* SBI extension registers are mapped as type 8 */ #define KVM_REG_RISCV_SBI_EXT (0x08 << KVM_REG_RISCV_TYPE_SHIFT) diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index 3efa2a77d2d95..c57c7fa260c22 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -409,55 +409,34 @@ static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu, return 0; } -static int kvm_riscv_vcpu_get_reg_isa_ext(struct kvm_vcpu *vcpu, - const struct kvm_one_reg *reg) +static int riscv_vcpu_get_isa_ext_single(struct kvm_vcpu *vcpu, + unsigned long reg_num, + unsigned long *reg_val) { - unsigned long __user *uaddr = - (unsigned long __user *)(unsigned long)reg->addr; - unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | - KVM_REG_SIZE_MASK | - KVM_REG_RISCV_ISA_EXT); - unsigned long reg_val = 0; unsigned long host_isa_ext; - if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) - return -EINVAL; - if (reg_num >= KVM_RISCV_ISA_EXT_MAX || reg_num >= ARRAY_SIZE(kvm_isa_ext_arr)) return -EINVAL; + *reg_val = 0; host_isa_ext = kvm_isa_ext_arr[reg_num]; if (__riscv_isa_extension_available(vcpu->arch.isa, host_isa_ext)) - reg_val = 1; /* Mark the given extension as available */ - - if (copy_to_user(uaddr, ®_val, KVM_REG_SIZE(reg->id))) - return -EFAULT; + *reg_val = 1; /* Mark the given extension as available */ return 0; } -static int kvm_riscv_vcpu_set_reg_isa_ext(struct kvm_vcpu *vcpu, - const struct kvm_one_reg *reg) +static int riscv_vcpu_set_isa_ext_single(struct kvm_vcpu *vcpu, + unsigned long reg_num, + unsigned long reg_val) { - unsigned long __user *uaddr = - (unsigned long __user *)(unsigned long)reg->addr; - unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | - KVM_REG_SIZE_MASK | - KVM_REG_RISCV_ISA_EXT); - unsigned long reg_val; unsigned long host_isa_ext; - if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) - return -EINVAL; - if (reg_num >= KVM_RISCV_ISA_EXT_MAX || reg_num >= ARRAY_SIZE(kvm_isa_ext_arr)) return -EINVAL; - if (copy_from_user(®_val, uaddr, KVM_REG_SIZE(reg->id))) - return -EFAULT; - host_isa_ext = kvm_isa_ext_arr[reg_num]; if (!__riscv_isa_extension_available(NULL, host_isa_ext)) return -EOPNOTSUPP; @@ -483,6 +462,122 @@ static int kvm_riscv_vcpu_set_reg_isa_ext(struct kvm_vcpu *vcpu, return 0; } +static int riscv_vcpu_get_isa_ext_multi(struct kvm_vcpu *vcpu, + unsigned long reg_num, + unsigned long *reg_val) +{ + unsigned long i, ext_id, ext_val; + + if (reg_num > KVM_REG_RISCV_ISA_MULTI_REG_LAST) + return -EINVAL; + + for (i = 0; i < BITS_PER_LONG; i++) { + ext_id = i + reg_num * BITS_PER_LONG; + if (ext_id >= KVM_RISCV_ISA_EXT_MAX) + break; + + ext_val = 0; + riscv_vcpu_get_isa_ext_single(vcpu, ext_id, &ext_val); + if (ext_val) + *reg_val |= KVM_REG_RISCV_ISA_MULTI_MASK(ext_id); + } + + return 0; +} + +static int riscv_vcpu_set_isa_ext_multi(struct kvm_vcpu *vcpu, + unsigned long reg_num, + unsigned long reg_val, bool enable) +{ + unsigned long i, ext_id; + + if (reg_num > KVM_REG_RISCV_ISA_MULTI_REG_LAST) + return -EINVAL; + + for_each_set_bit(i, ®_val, BITS_PER_LONG) { + ext_id = i + reg_num * BITS_PER_LONG; + if (ext_id >= KVM_RISCV_ISA_EXT_MAX) + break; + + riscv_vcpu_set_isa_ext_single(vcpu, ext_id, enable); + } + + return 0; +} + +static int kvm_riscv_vcpu_get_reg_isa_ext(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg) +{ + int rc; + unsigned long __user *uaddr = + (unsigned long __user *)(unsigned long)reg->addr; + unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | + KVM_REG_SIZE_MASK | + KVM_REG_RISCV_ISA_EXT); + unsigned long reg_val, reg_subtype; + + if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) + return -EINVAL; + + reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK; + reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK; + + reg_val = 0; + switch (reg_subtype) { + case KVM_REG_RISCV_ISA_SINGLE: + rc = riscv_vcpu_get_isa_ext_single(vcpu, reg_num, ®_val); + break; + case KVM_REG_RISCV_ISA_MULTI_EN: + case KVM_REG_RISCV_ISA_MULTI_DIS: + rc = riscv_vcpu_get_isa_ext_multi(vcpu, reg_num, ®_val); + if (!rc && reg_subtype == KVM_REG_RISCV_ISA_MULTI_DIS) + reg_val = ~reg_val; + break; + default: + rc = -EINVAL; + } + if (rc) + return rc; + + if (copy_to_user(uaddr, ®_val, KVM_REG_SIZE(reg->id))) + return -EFAULT; + + return 0; +} + +static int kvm_riscv_vcpu_set_reg_isa_ext(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg) +{ + unsigned long __user *uaddr = + (unsigned long __user *)(unsigned long)reg->addr; + unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | + KVM_REG_SIZE_MASK | + KVM_REG_RISCV_ISA_EXT); + unsigned long reg_val, reg_subtype; + + if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) + return -EINVAL; + + reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK; + reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK; + + if (copy_from_user(®_val, uaddr, KVM_REG_SIZE(reg->id))) + return -EFAULT; + + switch (reg_subtype) { + case KVM_REG_RISCV_ISA_SINGLE: + return riscv_vcpu_set_isa_ext_single(vcpu, reg_num, reg_val); + case KVM_REG_RISCV_SBI_MULTI_EN: + return riscv_vcpu_set_isa_ext_multi(vcpu, reg_num, reg_val, true); + case KVM_REG_RISCV_SBI_MULTI_DIS: + return riscv_vcpu_set_isa_ext_multi(vcpu, reg_num, reg_val, false); + default: + return -EINVAL; + } + + return 0; +} + int kvm_riscv_vcpu_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) { -- GitLab From 41716861e4251b202809fc57deaed3881934e062 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 12 Jul 2023 12:38:11 +0530 Subject: [PATCH 0906/3445] RISC-V: KVM: Allow Zba and Zbs extensions for Guest/VM We extend the KVM ISA extension ONE_REG interface to allow KVM user space to detect and enable Zba and Zbs extensions for Guest/VM. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- arch/riscv/include/uapi/asm/kvm.h | 2 ++ arch/riscv/kvm/vcpu_onereg.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h index 6c2285f865452..68f929d88f434 100644 --- a/arch/riscv/include/uapi/asm/kvm.h +++ b/arch/riscv/include/uapi/asm/kvm.h @@ -124,6 +124,8 @@ enum KVM_RISCV_ISA_EXT_ID { KVM_RISCV_ISA_EXT_SSAIA, KVM_RISCV_ISA_EXT_V, KVM_RISCV_ISA_EXT_SVNAPOT, + KVM_RISCV_ISA_EXT_ZBA, + KVM_RISCV_ISA_EXT_ZBS, KVM_RISCV_ISA_EXT_MAX, }; diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index c57c7fa260c22..4389ae050d33c 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -38,7 +38,9 @@ static const unsigned long kvm_isa_ext_arr[] = { KVM_ISA_EXT_ARR(SVINVAL), KVM_ISA_EXT_ARR(SVNAPOT), KVM_ISA_EXT_ARR(SVPBMT), + KVM_ISA_EXT_ARR(ZBA), KVM_ISA_EXT_ARR(ZBB), + KVM_ISA_EXT_ARR(ZBS), KVM_ISA_EXT_ARR(ZIHINTPAUSE), KVM_ISA_EXT_ARR(ZICBOM), KVM_ISA_EXT_ARR(ZICBOZ), @@ -82,7 +84,9 @@ static bool kvm_riscv_vcpu_isa_disable_allowed(unsigned long ext) case KVM_RISCV_ISA_EXT_SVINVAL: case KVM_RISCV_ISA_EXT_SVNAPOT: case KVM_RISCV_ISA_EXT_ZIHINTPAUSE: + case KVM_RISCV_ISA_EXT_ZBA: case KVM_RISCV_ISA_EXT_ZBB: + case KVM_RISCV_ISA_EXT_ZBS: return false; default: break; -- GitLab From 043cba064ecd2c3ccaf575c15caf6dd829c64e7b Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 12 Jul 2023 12:53:50 +0530 Subject: [PATCH 0907/3445] RISC-V: KVM: Allow Zicntr, Zicsr, Zifencei, and Zihpm for Guest/VM We extend the KVM ISA extension ONE_REG interface to allow KVM user space to detect and enable Zicntr, Zicsr, Zifencei, and Zihpm extensions for Guest/VM. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- arch/riscv/include/uapi/asm/kvm.h | 4 ++++ arch/riscv/kvm/vcpu_onereg.c | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h index 68f929d88f434..9c35e1427f733 100644 --- a/arch/riscv/include/uapi/asm/kvm.h +++ b/arch/riscv/include/uapi/asm/kvm.h @@ -126,6 +126,10 @@ enum KVM_RISCV_ISA_EXT_ID { KVM_RISCV_ISA_EXT_SVNAPOT, KVM_RISCV_ISA_EXT_ZBA, KVM_RISCV_ISA_EXT_ZBS, + KVM_RISCV_ISA_EXT_ZICNTR, + KVM_RISCV_ISA_EXT_ZICSR, + KVM_RISCV_ISA_EXT_ZIFENCEI, + KVM_RISCV_ISA_EXT_ZIHPM, KVM_RISCV_ISA_EXT_MAX, }; diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index 4389ae050d33c..0f75b6b3ced14 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -41,7 +41,11 @@ static const unsigned long kvm_isa_ext_arr[] = { KVM_ISA_EXT_ARR(ZBA), KVM_ISA_EXT_ARR(ZBB), KVM_ISA_EXT_ARR(ZBS), + KVM_ISA_EXT_ARR(ZICNTR), + KVM_ISA_EXT_ARR(ZICSR), + KVM_ISA_EXT_ARR(ZIFENCEI), KVM_ISA_EXT_ARR(ZIHINTPAUSE), + KVM_ISA_EXT_ARR(ZIHPM), KVM_ISA_EXT_ARR(ZICBOM), KVM_ISA_EXT_ARR(ZICBOZ), }; @@ -83,7 +87,11 @@ static bool kvm_riscv_vcpu_isa_disable_allowed(unsigned long ext) case KVM_RISCV_ISA_EXT_SSTC: case KVM_RISCV_ISA_EXT_SVINVAL: case KVM_RISCV_ISA_EXT_SVNAPOT: + case KVM_RISCV_ISA_EXT_ZICNTR: + case KVM_RISCV_ISA_EXT_ZICSR: + case KVM_RISCV_ISA_EXT_ZIFENCEI: case KVM_RISCV_ISA_EXT_ZIHINTPAUSE: + case KVM_RISCV_ISA_EXT_ZIHPM: case KVM_RISCV_ISA_EXT_ZBA: case KVM_RISCV_ISA_EXT_ZBB: case KVM_RISCV_ISA_EXT_ZBS: -- GitLab From d2064d4a6e3a565879da196947fb35cc7b1f3256 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 12 Jul 2023 15:33:12 +0530 Subject: [PATCH 0908/3445] RISC-V: KVM: Sort ISA extensions alphabetically in ONE_REG interface Let us sort isa extensions alphabetically in kvm_isa_ext_arr[] and kvm_riscv_vcpu_isa_disable_allowed() so that future insertions are more predictable. Signed-off-by: Anup Patel Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu_onereg.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index 0f75b6b3ced14..0dc2c2cecb450 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -24,6 +24,7 @@ /* Mapping between KVM ISA Extension ID & Host ISA extension ID */ static const unsigned long kvm_isa_ext_arr[] = { + /* Single letter extensions (alphabetically sorted) */ [KVM_RISCV_ISA_EXT_A] = RISCV_ISA_EXT_a, [KVM_RISCV_ISA_EXT_C] = RISCV_ISA_EXT_c, [KVM_RISCV_ISA_EXT_D] = RISCV_ISA_EXT_d, @@ -32,7 +33,7 @@ static const unsigned long kvm_isa_ext_arr[] = { [KVM_RISCV_ISA_EXT_I] = RISCV_ISA_EXT_i, [KVM_RISCV_ISA_EXT_M] = RISCV_ISA_EXT_m, [KVM_RISCV_ISA_EXT_V] = RISCV_ISA_EXT_v, - + /* Multi letter extensions (alphabetically sorted) */ KVM_ISA_EXT_ARR(SSAIA), KVM_ISA_EXT_ARR(SSTC), KVM_ISA_EXT_ARR(SVINVAL), @@ -41,13 +42,13 @@ static const unsigned long kvm_isa_ext_arr[] = { KVM_ISA_EXT_ARR(ZBA), KVM_ISA_EXT_ARR(ZBB), KVM_ISA_EXT_ARR(ZBS), + KVM_ISA_EXT_ARR(ZICBOM), + KVM_ISA_EXT_ARR(ZICBOZ), KVM_ISA_EXT_ARR(ZICNTR), KVM_ISA_EXT_ARR(ZICSR), KVM_ISA_EXT_ARR(ZIFENCEI), KVM_ISA_EXT_ARR(ZIHINTPAUSE), KVM_ISA_EXT_ARR(ZIHPM), - KVM_ISA_EXT_ARR(ZICBOM), - KVM_ISA_EXT_ARR(ZICBOZ), }; static unsigned long kvm_riscv_vcpu_base2isa_ext(unsigned long base_ext) @@ -87,14 +88,14 @@ static bool kvm_riscv_vcpu_isa_disable_allowed(unsigned long ext) case KVM_RISCV_ISA_EXT_SSTC: case KVM_RISCV_ISA_EXT_SVINVAL: case KVM_RISCV_ISA_EXT_SVNAPOT: + case KVM_RISCV_ISA_EXT_ZBA: + case KVM_RISCV_ISA_EXT_ZBB: + case KVM_RISCV_ISA_EXT_ZBS: case KVM_RISCV_ISA_EXT_ZICNTR: case KVM_RISCV_ISA_EXT_ZICSR: case KVM_RISCV_ISA_EXT_ZIFENCEI: case KVM_RISCV_ISA_EXT_ZIHINTPAUSE: case KVM_RISCV_ISA_EXT_ZIHPM: - case KVM_RISCV_ISA_EXT_ZBA: - case KVM_RISCV_ISA_EXT_ZBB: - case KVM_RISCV_ISA_EXT_ZBS: return false; default: break; -- GitLab From 2776421e6839b67c34261861b169b7ee737b4c00 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Fri, 28 Jul 2023 18:01:22 -0300 Subject: [PATCH 0909/3445] RISC-V: KVM: provide UAPI for host SATP mode KVM userspaces need to be aware of the host SATP to allow them to advertise it back to the guest OS. Since this information is used to build the guest FDT we can't wait for the SATP reg to be readable. We just need to read the SATP mode, thus we can use the existing 'satp_mode' global that represents the SATP reg with MODE set and both ASID and PPN cleared. E.g. for a 32 bit host running with sv32 satp_mode is 0x80000000, for a 64 bit host running sv57 satp_mode is 0xa000000000000000, and so on. Add a new userspace virtual config register 'satp_mode' to allow userspace to read the current SATP mode the host is using with GET_ONE_REG API before spinning the vcpu. 'satp_mode' can't be changed via KVM, so SET_ONE_REG is allowed as long as userspace writes the existing 'satp_mode'. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- arch/riscv/include/asm/csr.h | 2 ++ arch/riscv/include/uapi/asm/kvm.h | 1 + arch/riscv/kvm/vcpu_onereg.c | 7 +++++++ 3 files changed, 10 insertions(+) diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h index 7bac43a3176ed..777cb8299551c 100644 --- a/arch/riscv/include/asm/csr.h +++ b/arch/riscv/include/asm/csr.h @@ -54,6 +54,7 @@ #ifndef CONFIG_64BIT #define SATP_PPN _AC(0x003FFFFF, UL) #define SATP_MODE_32 _AC(0x80000000, UL) +#define SATP_MODE_SHIFT 31 #define SATP_ASID_BITS 9 #define SATP_ASID_SHIFT 22 #define SATP_ASID_MASK _AC(0x1FF, UL) @@ -62,6 +63,7 @@ #define SATP_MODE_39 _AC(0x8000000000000000, UL) #define SATP_MODE_48 _AC(0x9000000000000000, UL) #define SATP_MODE_57 _AC(0xa000000000000000, UL) +#define SATP_MODE_SHIFT 60 #define SATP_ASID_BITS 16 #define SATP_ASID_SHIFT 44 #define SATP_ASID_MASK _AC(0xFFFF, UL) diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h index 9c35e1427f733..992c5e4071049 100644 --- a/arch/riscv/include/uapi/asm/kvm.h +++ b/arch/riscv/include/uapi/asm/kvm.h @@ -55,6 +55,7 @@ struct kvm_riscv_config { unsigned long marchid; unsigned long mimpid; unsigned long zicboz_block_size; + unsigned long satp_mode; }; /* CORE registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */ diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index 0dc2c2cecb450..85773e858120f 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -152,6 +152,9 @@ static int kvm_riscv_vcpu_get_reg_config(struct kvm_vcpu *vcpu, case KVM_REG_RISCV_CONFIG_REG(mimpid): reg_val = vcpu->arch.mimpid; break; + case KVM_REG_RISCV_CONFIG_REG(satp_mode): + reg_val = satp_mode >> SATP_MODE_SHIFT; + break; default: return -EINVAL; } @@ -234,6 +237,10 @@ static int kvm_riscv_vcpu_set_reg_config(struct kvm_vcpu *vcpu, else return -EBUSY; break; + case KVM_REG_RISCV_CONFIG_REG(satp_mode): + if (reg_val != (satp_mode >> SATP_MODE_SHIFT)) + return -EINVAL; + break; default: return -EINVAL; } -- GitLab From 2a88f38cd58d026c0e13f4aaa495965d4e9626b9 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Thu, 3 Aug 2023 13:32:53 -0300 Subject: [PATCH 0910/3445] RISC-V: KVM: return ENOENT in *_one_reg() when reg is unknown get_one_reg() and set_one_reg() are returning EINVAL errors for almost everything: if a reg doesn't exist, if a reg ID is malformatted, if the associated CPU extension that implements the reg isn't present in the host, and for set_one_reg() if the value being written is invalid. This isn't wrong according to the existing KVM API docs (EINVAL can be used when there's no such register) but adding more ENOENT instances will make easier for userspace to understand what went wrong. Existing userspaces can be affected by this error code change. We checked a few. As of current upstream code, crosvm doesn't check for any particular errno code when using kvm_(get|set)_one_reg(). Neither does QEMU. rust-vmm doesn't have kvm-riscv support yet. Thus we have a good chance of changing these error codes now while the KVM RISC-V ecosystem is still new, minimizing user impact. Change all get_one_reg() and set_one_reg() implementations to return -ENOENT at all "no such register" cases. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- arch/riscv/kvm/aia.c | 4 ++-- arch/riscv/kvm/vcpu_fp.c | 12 ++++++------ arch/riscv/kvm/vcpu_onereg.c | 36 ++++++++++++++++++------------------ arch/riscv/kvm/vcpu_sbi.c | 16 +++++++++------- arch/riscv/kvm/vcpu_timer.c | 8 ++++---- 5 files changed, 39 insertions(+), 37 deletions(-) diff --git a/arch/riscv/kvm/aia.c b/arch/riscv/kvm/aia.c index 585a3b42c52c6..74bb27440527b 100644 --- a/arch/riscv/kvm/aia.c +++ b/arch/riscv/kvm/aia.c @@ -176,7 +176,7 @@ int kvm_riscv_vcpu_aia_get_csr(struct kvm_vcpu *vcpu, struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; if (reg_num >= sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long)) - return -EINVAL; + return -ENOENT; *out_val = 0; if (kvm_riscv_aia_available()) @@ -192,7 +192,7 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu, struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; if (reg_num >= sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long)) - return -EINVAL; + return -ENOENT; if (kvm_riscv_aia_available()) { ((unsigned long *)csr)[reg_num] = val; diff --git a/arch/riscv/kvm/vcpu_fp.c b/arch/riscv/kvm/vcpu_fp.c index 9d8cbc42057a9..08ba48a395aa2 100644 --- a/arch/riscv/kvm/vcpu_fp.c +++ b/arch/riscv/kvm/vcpu_fp.c @@ -96,7 +96,7 @@ int kvm_riscv_vcpu_get_reg_fp(struct kvm_vcpu *vcpu, reg_num <= KVM_REG_RISCV_FP_F_REG(f[31])) reg_val = &cntx->fp.f.f[reg_num]; else - return -EINVAL; + return -ENOENT; } else if ((rtype == KVM_REG_RISCV_FP_D) && riscv_isa_extension_available(vcpu->arch.isa, d)) { if (reg_num == KVM_REG_RISCV_FP_D_REG(fcsr)) { @@ -109,9 +109,9 @@ int kvm_riscv_vcpu_get_reg_fp(struct kvm_vcpu *vcpu, return -EINVAL; reg_val = &cntx->fp.d.f[reg_num]; } else - return -EINVAL; + return -ENOENT; } else - return -EINVAL; + return -ENOENT; if (copy_to_user(uaddr, reg_val, KVM_REG_SIZE(reg->id))) return -EFAULT; @@ -141,7 +141,7 @@ int kvm_riscv_vcpu_set_reg_fp(struct kvm_vcpu *vcpu, reg_num <= KVM_REG_RISCV_FP_F_REG(f[31])) reg_val = &cntx->fp.f.f[reg_num]; else - return -EINVAL; + return -ENOENT; } else if ((rtype == KVM_REG_RISCV_FP_D) && riscv_isa_extension_available(vcpu->arch.isa, d)) { if (reg_num == KVM_REG_RISCV_FP_D_REG(fcsr)) { @@ -154,9 +154,9 @@ int kvm_riscv_vcpu_set_reg_fp(struct kvm_vcpu *vcpu, return -EINVAL; reg_val = &cntx->fp.d.f[reg_num]; } else - return -EINVAL; + return -ENOENT; } else - return -EINVAL; + return -ENOENT; if (copy_from_user(reg_val, uaddr, KVM_REG_SIZE(reg->id))) return -EFAULT; diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index 85773e858120f..456e9f31441a4 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -156,7 +156,7 @@ static int kvm_riscv_vcpu_get_reg_config(struct kvm_vcpu *vcpu, reg_val = satp_mode >> SATP_MODE_SHIFT; break; default: - return -EINVAL; + return -ENOENT; } if (copy_to_user(uaddr, ®_val, KVM_REG_SIZE(reg->id))) @@ -242,7 +242,7 @@ static int kvm_riscv_vcpu_set_reg_config(struct kvm_vcpu *vcpu, return -EINVAL; break; default: - return -EINVAL; + return -ENOENT; } return 0; @@ -262,7 +262,7 @@ static int kvm_riscv_vcpu_get_reg_core(struct kvm_vcpu *vcpu, if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) return -EINVAL; if (reg_num >= sizeof(struct kvm_riscv_core) / sizeof(unsigned long)) - return -EINVAL; + return -ENOENT; if (reg_num == KVM_REG_RISCV_CORE_REG(regs.pc)) reg_val = cntx->sepc; @@ -273,7 +273,7 @@ static int kvm_riscv_vcpu_get_reg_core(struct kvm_vcpu *vcpu, reg_val = (cntx->sstatus & SR_SPP) ? KVM_RISCV_MODE_S : KVM_RISCV_MODE_U; else - return -EINVAL; + return -ENOENT; if (copy_to_user(uaddr, ®_val, KVM_REG_SIZE(reg->id))) return -EFAULT; @@ -295,7 +295,7 @@ static int kvm_riscv_vcpu_set_reg_core(struct kvm_vcpu *vcpu, if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) return -EINVAL; if (reg_num >= sizeof(struct kvm_riscv_core) / sizeof(unsigned long)) - return -EINVAL; + return -ENOENT; if (copy_from_user(®_val, uaddr, KVM_REG_SIZE(reg->id))) return -EFAULT; @@ -311,7 +311,7 @@ static int kvm_riscv_vcpu_set_reg_core(struct kvm_vcpu *vcpu, else cntx->sstatus &= ~SR_SPP; } else - return -EINVAL; + return -ENOENT; return 0; } @@ -323,7 +323,7 @@ static int kvm_riscv_vcpu_general_get_csr(struct kvm_vcpu *vcpu, struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; if (reg_num >= sizeof(struct kvm_riscv_csr) / sizeof(unsigned long)) - return -EINVAL; + return -ENOENT; if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) { kvm_riscv_vcpu_flush_interrupts(vcpu); @@ -342,7 +342,7 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu, struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; if (reg_num >= sizeof(struct kvm_riscv_csr) / sizeof(unsigned long)) - return -EINVAL; + return -ENOENT; if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) { reg_val &= VSIP_VALID_MASK; @@ -381,7 +381,7 @@ static int kvm_riscv_vcpu_get_reg_csr(struct kvm_vcpu *vcpu, rc = kvm_riscv_vcpu_aia_get_csr(vcpu, reg_num, ®_val); break; default: - rc = -EINVAL; + rc = -ENOENT; break; } if (rc) @@ -420,7 +420,7 @@ static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu, rc = kvm_riscv_vcpu_aia_set_csr(vcpu, reg_num, reg_val); break; default: - rc = -EINVAL; + rc = -ENOENT; break; } if (rc) @@ -437,7 +437,7 @@ static int riscv_vcpu_get_isa_ext_single(struct kvm_vcpu *vcpu, if (reg_num >= KVM_RISCV_ISA_EXT_MAX || reg_num >= ARRAY_SIZE(kvm_isa_ext_arr)) - return -EINVAL; + return -ENOENT; *reg_val = 0; host_isa_ext = kvm_isa_ext_arr[reg_num]; @@ -455,7 +455,7 @@ static int riscv_vcpu_set_isa_ext_single(struct kvm_vcpu *vcpu, if (reg_num >= KVM_RISCV_ISA_EXT_MAX || reg_num >= ARRAY_SIZE(kvm_isa_ext_arr)) - return -EINVAL; + return -ENOENT; host_isa_ext = kvm_isa_ext_arr[reg_num]; if (!__riscv_isa_extension_available(NULL, host_isa_ext)) @@ -489,7 +489,7 @@ static int riscv_vcpu_get_isa_ext_multi(struct kvm_vcpu *vcpu, unsigned long i, ext_id, ext_val; if (reg_num > KVM_REG_RISCV_ISA_MULTI_REG_LAST) - return -EINVAL; + return -ENOENT; for (i = 0; i < BITS_PER_LONG; i++) { ext_id = i + reg_num * BITS_PER_LONG; @@ -512,7 +512,7 @@ static int riscv_vcpu_set_isa_ext_multi(struct kvm_vcpu *vcpu, unsigned long i, ext_id; if (reg_num > KVM_REG_RISCV_ISA_MULTI_REG_LAST) - return -EINVAL; + return -ENOENT; for_each_set_bit(i, ®_val, BITS_PER_LONG) { ext_id = i + reg_num * BITS_PER_LONG; @@ -554,7 +554,7 @@ static int kvm_riscv_vcpu_get_reg_isa_ext(struct kvm_vcpu *vcpu, reg_val = ~reg_val; break; default: - rc = -EINVAL; + rc = -ENOENT; } if (rc) return rc; @@ -592,7 +592,7 @@ static int kvm_riscv_vcpu_set_reg_isa_ext(struct kvm_vcpu *vcpu, case KVM_REG_RISCV_SBI_MULTI_DIS: return riscv_vcpu_set_isa_ext_multi(vcpu, reg_num, reg_val, false); default: - return -EINVAL; + return -ENOENT; } return 0; @@ -627,7 +627,7 @@ int kvm_riscv_vcpu_set_reg(struct kvm_vcpu *vcpu, break; } - return -EINVAL; + return -ENOENT; } int kvm_riscv_vcpu_get_reg(struct kvm_vcpu *vcpu, @@ -659,5 +659,5 @@ int kvm_riscv_vcpu_get_reg(struct kvm_vcpu *vcpu, break; } - return -EINVAL; + return -ENOENT; } diff --git a/arch/riscv/kvm/vcpu_sbi.c b/arch/riscv/kvm/vcpu_sbi.c index 7b46e04fb6675..9cd97091c7233 100644 --- a/arch/riscv/kvm/vcpu_sbi.c +++ b/arch/riscv/kvm/vcpu_sbi.c @@ -140,8 +140,10 @@ static int riscv_vcpu_set_sbi_ext_single(struct kvm_vcpu *vcpu, const struct kvm_riscv_sbi_extension_entry *sext = NULL; struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context; - if (reg_num >= KVM_RISCV_SBI_EXT_MAX || - (reg_val != 1 && reg_val != 0)) + if (reg_num >= KVM_RISCV_SBI_EXT_MAX) + return -ENOENT; + + if (reg_val != 1 && reg_val != 0) return -EINVAL; for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) { @@ -175,7 +177,7 @@ static int riscv_vcpu_get_sbi_ext_single(struct kvm_vcpu *vcpu, struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context; if (reg_num >= KVM_RISCV_SBI_EXT_MAX) - return -EINVAL; + return -ENOENT; for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) { if (sbi_ext[i].ext_idx == reg_num) { @@ -206,7 +208,7 @@ static int riscv_vcpu_set_sbi_ext_multi(struct kvm_vcpu *vcpu, unsigned long i, ext_id; if (reg_num > KVM_REG_RISCV_SBI_MULTI_REG_LAST) - return -EINVAL; + return -ENOENT; for_each_set_bit(i, ®_val, BITS_PER_LONG) { ext_id = i + reg_num * BITS_PER_LONG; @@ -226,7 +228,7 @@ static int riscv_vcpu_get_sbi_ext_multi(struct kvm_vcpu *vcpu, unsigned long i, ext_id, ext_val; if (reg_num > KVM_REG_RISCV_SBI_MULTI_REG_LAST) - return -EINVAL; + return -ENOENT; for (i = 0; i < BITS_PER_LONG; i++) { ext_id = i + reg_num * BITS_PER_LONG; @@ -272,7 +274,7 @@ int kvm_riscv_vcpu_set_reg_sbi_ext(struct kvm_vcpu *vcpu, case KVM_REG_RISCV_SBI_MULTI_DIS: return riscv_vcpu_set_sbi_ext_multi(vcpu, reg_num, reg_val, false); default: - return -EINVAL; + return -ENOENT; } return 0; @@ -307,7 +309,7 @@ int kvm_riscv_vcpu_get_reg_sbi_ext(struct kvm_vcpu *vcpu, reg_val = ~reg_val; break; default: - rc = -EINVAL; + rc = -ENOENT; } if (rc) return rc; diff --git a/arch/riscv/kvm/vcpu_timer.c b/arch/riscv/kvm/vcpu_timer.c index 3ac2ff6a65dac..527d269cafffc 100644 --- a/arch/riscv/kvm/vcpu_timer.c +++ b/arch/riscv/kvm/vcpu_timer.c @@ -170,7 +170,7 @@ int kvm_riscv_vcpu_get_reg_timer(struct kvm_vcpu *vcpu, if (KVM_REG_SIZE(reg->id) != sizeof(u64)) return -EINVAL; if (reg_num >= sizeof(struct kvm_riscv_timer) / sizeof(u64)) - return -EINVAL; + return -ENOENT; switch (reg_num) { case KVM_REG_RISCV_TIMER_REG(frequency): @@ -187,7 +187,7 @@ int kvm_riscv_vcpu_get_reg_timer(struct kvm_vcpu *vcpu, KVM_RISCV_TIMER_STATE_OFF; break; default: - return -EINVAL; + return -ENOENT; } if (copy_to_user(uaddr, ®_val, KVM_REG_SIZE(reg->id))) @@ -211,7 +211,7 @@ int kvm_riscv_vcpu_set_reg_timer(struct kvm_vcpu *vcpu, if (KVM_REG_SIZE(reg->id) != sizeof(u64)) return -EINVAL; if (reg_num >= sizeof(struct kvm_riscv_timer) / sizeof(u64)) - return -EINVAL; + return -ENOENT; if (copy_from_user(®_val, uaddr, KVM_REG_SIZE(reg->id))) return -EFAULT; @@ -233,7 +233,7 @@ int kvm_riscv_vcpu_set_reg_timer(struct kvm_vcpu *vcpu, ret = kvm_riscv_vcpu_timer_cancel(t); break; default: - ret = -EINVAL; + ret = -ENOENT; break; } -- GitLab From a044ef71043ebc23903f657fd51b10783d34918b Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Thu, 3 Aug 2023 13:32:54 -0300 Subject: [PATCH 0911/3445] RISC-V: KVM: use ENOENT in *_one_reg() when extension is unavailable Following a similar logic as the previous patch let's minimize the EINVAL usage in *_one_reg() APIs by using ENOENT when an extension that implements the reg is not available. For consistency we're also replacing an EOPNOTSUPP instance that should be an ENOENT since it's an "extension is not available" error. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu_onereg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index 456e9f31441a4..1ffd8ac3800a1 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -135,12 +135,12 @@ static int kvm_riscv_vcpu_get_reg_config(struct kvm_vcpu *vcpu, break; case KVM_REG_RISCV_CONFIG_REG(zicbom_block_size): if (!riscv_isa_extension_available(vcpu->arch.isa, ZICBOM)) - return -EINVAL; + return -ENOENT; reg_val = riscv_cbom_block_size; break; case KVM_REG_RISCV_CONFIG_REG(zicboz_block_size): if (!riscv_isa_extension_available(vcpu->arch.isa, ZICBOZ)) - return -EINVAL; + return -ENOENT; reg_val = riscv_cboz_block_size; break; case KVM_REG_RISCV_CONFIG_REG(mvendorid): @@ -459,7 +459,7 @@ static int riscv_vcpu_set_isa_ext_single(struct kvm_vcpu *vcpu, host_isa_ext = kvm_isa_ext_arr[reg_num]; if (!__riscv_isa_extension_available(NULL, host_isa_ext)) - return -EOPNOTSUPP; + return -ENOENT; if (!vcpu->arch.ran_atleast_once) { /* -- GitLab From e29f57911d61bcbbe442c72933c606225d3d4d68 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Thu, 3 Aug 2023 13:32:55 -0300 Subject: [PATCH 0912/3445] RISC-V: KVM: do not EOPNOTSUPP in set_one_reg() zicbo(m|z) zicbom_block_size and zicboz_block_size have a peculiar API: they can be read via get_one_reg() but any write will return a EOPNOTSUPP. It makes sense to return a 'not supported' error since both values can't be changed, but as far as userspace goes they're regs that are throwing the same EOPNOTSUPP error even if they were read beforehand via get_one_reg(), even if the same read value is being written back. EOPNOTSUPP is also returned even if ZICBOM/ZICBOZ aren't enabled in the host. Change both to work more like their counterparts in get_one_reg() and return -ENOENT if their respective extensions aren't available. After that, check if the userspace is written a valid value (i.e. the host value). Throw an -EINVAL if that's not case, let it slide otherwise. This allows both regs to be read/written by userspace in a 'lazy' manner, as long as the userspace doesn't change the reg vals. Suggested-by: Andrew Jones Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu_onereg.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index 1ffd8ac3800a1..e06256dd8d246 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -216,9 +216,17 @@ static int kvm_riscv_vcpu_set_reg_config(struct kvm_vcpu *vcpu, } break; case KVM_REG_RISCV_CONFIG_REG(zicbom_block_size): - return -EOPNOTSUPP; + if (!riscv_isa_extension_available(vcpu->arch.isa, ZICBOM)) + return -ENOENT; + if (reg_val != riscv_cbom_block_size) + return -EINVAL; + break; case KVM_REG_RISCV_CONFIG_REG(zicboz_block_size): - return -EOPNOTSUPP; + if (!riscv_isa_extension_available(vcpu->arch.isa, ZICBOZ)) + return -ENOENT; + if (reg_val != riscv_cboz_block_size) + return -EINVAL; + break; case KVM_REG_RISCV_CONFIG_REG(mvendorid): if (!vcpu->arch.ran_atleast_once) vcpu->arch.mvendorid = reg_val; -- GitLab From 432a8b35cc23d3af9c60e9c0d191d7ff737afbdc Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Thu, 3 Aug 2023 13:32:56 -0300 Subject: [PATCH 0913/3445] RISC-V: KVM: do not EOPNOTSUPP in set KVM_REG_RISCV_TIMER_REG The KVM_REG_RISCV_TIMER_REG can be read via get_one_reg(). But trying to write anything in this reg via set_one_reg() results in an EOPNOTSUPP. Change the API to behave like cbom_block_size: instead of always erroring out with EOPNOTSUPP, allow userspace to write the same value (riscv_timebase) back, throwing an EINVAL if a different value is attempted. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu_timer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/riscv/kvm/vcpu_timer.c b/arch/riscv/kvm/vcpu_timer.c index 527d269cafffc..75486b25ac45a 100644 --- a/arch/riscv/kvm/vcpu_timer.c +++ b/arch/riscv/kvm/vcpu_timer.c @@ -218,7 +218,8 @@ int kvm_riscv_vcpu_set_reg_timer(struct kvm_vcpu *vcpu, switch (reg_num) { case KVM_REG_RISCV_TIMER_REG(frequency): - ret = -EOPNOTSUPP; + if (reg_val != riscv_timebase) + return -EINVAL; break; case KVM_REG_RISCV_TIMER_REG(time): gt->time_delta = reg_val - get_cycles64(); -- GitLab From d57304bbfb742bf744d2cd4dc3a08ce3fbfba787 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Thu, 3 Aug 2023 13:32:57 -0300 Subject: [PATCH 0914/3445] RISC-V: KVM: use EBUSY when !vcpu->arch.ran_atleast_once vcpu_set_reg_config() and vcpu_set_reg_isa_ext() is throwing an EOPNOTSUPP error when !vcpu->arch.ran_atleast_once. In similar cases we're throwing an EBUSY error, like in mvendorid/marchid/mimpid set_reg(). EOPNOTSUPP has a conotation of finality. EBUSY is more adequate in this case since its a condition/error related to the vcpu lifecycle. Change these EOPNOTSUPP instances to EBUSY. Suggested-by: Andrew Jones Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu_onereg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index e06256dd8d246..971a2eb83180b 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -212,7 +212,7 @@ static int kvm_riscv_vcpu_set_reg_config(struct kvm_vcpu *vcpu, vcpu->arch.isa[0] = reg_val; kvm_riscv_vcpu_fp_reset(vcpu); } else { - return -EOPNOTSUPP; + return -EBUSY; } break; case KVM_REG_RISCV_CONFIG_REG(zicbom_block_size): @@ -484,7 +484,7 @@ static int riscv_vcpu_set_isa_ext_single(struct kvm_vcpu *vcpu, return -EINVAL; kvm_riscv_vcpu_fp_reset(vcpu); } else { - return -EOPNOTSUPP; + return -EBUSY; } return 0; -- GitLab From bea8d23713a2b2dc07ae9d7325b1269dff8c8a1f Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Thu, 3 Aug 2023 13:32:58 -0300 Subject: [PATCH 0915/3445] RISC-V: KVM: avoid EBUSY when writing same ISA val kvm_riscv_vcpu_set_reg_config() will return -EBUSY if the ISA config reg is being written after the VCPU ran at least once. The same restriction isn't placed in kvm_riscv_vcpu_get_reg_config(), so there's a chance that we'll -EBUSY out on an ISA config reg write even if the userspace intended no changes to it. We'll allow the same form of 'lazy writing' that registers such as zicbom/zicboz_block_size supports: avoid erroring out if userspace made no changes to the ISA config reg. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu_onereg.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index 971a2eb83180b..a0b0364b038fe 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -190,6 +190,13 @@ static int kvm_riscv_vcpu_set_reg_config(struct kvm_vcpu *vcpu, if (fls(reg_val) >= RISCV_ISA_EXT_BASE) return -EINVAL; + /* + * Return early (i.e. do nothing) if reg_val is the same + * value retrievable via kvm_riscv_vcpu_get_reg_config(). + */ + if (reg_val == (vcpu->arch.isa[0] & KVM_RISCV_BASE_ISA_MASK)) + break; + if (!vcpu->arch.ran_atleast_once) { /* Ignore the enable/disable request for certain extensions */ for (i = 0; i < RISCV_ISA_EXT_BASE; i++) { -- GitLab From 63bd660657efade03270c8cc7e3d9b6993350e56 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Thu, 3 Aug 2023 13:32:59 -0300 Subject: [PATCH 0916/3445] RISC-V: KVM: avoid EBUSY when writing the same machine ID val Right now we do not allow any write in mvendorid/marchid/mimpid if the vcpu already started, preventing these regs to be changed. However, if userspace doesn't change them, an alternative is to consider the reg write a no-op and avoid erroring out altogether. Userpace can then be oblivious about KVM internals if no changes were intended in the first place. Allow the same form of 'lazy writing' that registers such as zicbom/zicboz_block_size supports: avoid erroring out if userspace makes no changes in mvendorid/marchid/mimpid during reg write. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu_onereg.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index a0b0364b038fe..81cb6b2784db2 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -235,18 +235,24 @@ static int kvm_riscv_vcpu_set_reg_config(struct kvm_vcpu *vcpu, return -EINVAL; break; case KVM_REG_RISCV_CONFIG_REG(mvendorid): + if (reg_val == vcpu->arch.mvendorid) + break; if (!vcpu->arch.ran_atleast_once) vcpu->arch.mvendorid = reg_val; else return -EBUSY; break; case KVM_REG_RISCV_CONFIG_REG(marchid): + if (reg_val == vcpu->arch.marchid) + break; if (!vcpu->arch.ran_atleast_once) vcpu->arch.marchid = reg_val; else return -EBUSY; break; case KVM_REG_RISCV_CONFIG_REG(mimpid): + if (reg_val == vcpu->arch.mimpid) + break; if (!vcpu->arch.ran_atleast_once) vcpu->arch.mimpid = reg_val; else -- GitLab From 1099c80906d358db542c64aba370291ae4b932b7 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Thu, 3 Aug 2023 13:33:00 -0300 Subject: [PATCH 0917/3445] RISC-V: KVM: avoid EBUSY when writing the same isa_ext val riscv_vcpu_set_isa_ext_single() will prevent any write of isa_ext regs if the vcpu already started spinning. But if there's no extension state (enabled/disabled) made by the userspace, there's no need to -EBUSY out - we can treat the operation as a no-op. zicbom/zicboz_block_size, ISA config reg and mvendorid/march/mimpid already works in a more permissive manner w.r.t userspace writes being a no-op, so let's do the same with isa_ext writes. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu_onereg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index 81cb6b2784db2..989ea32dbcbee 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -482,6 +482,9 @@ static int riscv_vcpu_set_isa_ext_single(struct kvm_vcpu *vcpu, if (!__riscv_isa_extension_available(NULL, host_isa_ext)) return -ENOENT; + if (reg_val == test_bit(host_isa_ext, vcpu->arch.isa)) + return 0; + if (!vcpu->arch.ran_atleast_once) { /* * All multi-letter extension and a few single letter -- GitLab From 1deaf754f5310e348e6386e75b7f16a0089fa3b7 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 3 Aug 2023 13:33:01 -0300 Subject: [PATCH 0918/3445] RISC-V: KVM: Improve vector save/restore errors kvm_riscv_vcpu_(get/set)_reg_vector() now returns ENOENT if V is not available, EINVAL if reg type is not of VECTOR type, and any error that might be thrown by kvm_riscv_vcpu_vreg_addr(). Signed-off-by: Andrew Jones Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu_vector.c | 60 ++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/arch/riscv/kvm/vcpu_vector.c b/arch/riscv/kvm/vcpu_vector.c index edd2eecbddc2e..39c5bceb4d1b0 100644 --- a/arch/riscv/kvm/vcpu_vector.c +++ b/arch/riscv/kvm/vcpu_vector.c @@ -91,44 +91,44 @@ void kvm_riscv_vcpu_free_vector_context(struct kvm_vcpu *vcpu) } #endif -static void *kvm_riscv_vcpu_vreg_addr(struct kvm_vcpu *vcpu, +static int kvm_riscv_vcpu_vreg_addr(struct kvm_vcpu *vcpu, unsigned long reg_num, - size_t reg_size) + size_t reg_size, + void **reg_val) { struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; - void *reg_val; size_t vlenb = riscv_v_vsize / 32; if (reg_num < KVM_REG_RISCV_VECTOR_REG(0)) { if (reg_size != sizeof(unsigned long)) - return NULL; + return -EINVAL; switch (reg_num) { case KVM_REG_RISCV_VECTOR_CSR_REG(vstart): - reg_val = &cntx->vector.vstart; + *reg_val = &cntx->vector.vstart; break; case KVM_REG_RISCV_VECTOR_CSR_REG(vl): - reg_val = &cntx->vector.vl; + *reg_val = &cntx->vector.vl; break; case KVM_REG_RISCV_VECTOR_CSR_REG(vtype): - reg_val = &cntx->vector.vtype; + *reg_val = &cntx->vector.vtype; break; case KVM_REG_RISCV_VECTOR_CSR_REG(vcsr): - reg_val = &cntx->vector.vcsr; + *reg_val = &cntx->vector.vcsr; break; case KVM_REG_RISCV_VECTOR_CSR_REG(datap): default: - return NULL; + return -ENOENT; } } else if (reg_num <= KVM_REG_RISCV_VECTOR_REG(31)) { if (reg_size != vlenb) - return NULL; - reg_val = cntx->vector.datap + return -EINVAL; + *reg_val = cntx->vector.datap + (reg_num - KVM_REG_RISCV_VECTOR_REG(0)) * vlenb; } else { - return NULL; + return -ENOENT; } - return reg_val; + return 0; } int kvm_riscv_vcpu_get_reg_vector(struct kvm_vcpu *vcpu, @@ -141,17 +141,20 @@ int kvm_riscv_vcpu_get_reg_vector(struct kvm_vcpu *vcpu, unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | rtype); - void *reg_val = NULL; size_t reg_size = KVM_REG_SIZE(reg->id); + void *reg_val; + int rc; - if (rtype == KVM_REG_RISCV_VECTOR && - riscv_isa_extension_available(isa, v)) { - reg_val = kvm_riscv_vcpu_vreg_addr(vcpu, reg_num, reg_size); - } - - if (!reg_val) + if (rtype != KVM_REG_RISCV_VECTOR) return -EINVAL; + if (!riscv_isa_extension_available(isa, v)) + return -ENOENT; + + rc = kvm_riscv_vcpu_vreg_addr(vcpu, reg_num, reg_size, ®_val); + if (rc) + return rc; + if (copy_to_user(uaddr, reg_val, reg_size)) return -EFAULT; @@ -168,17 +171,20 @@ int kvm_riscv_vcpu_set_reg_vector(struct kvm_vcpu *vcpu, unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | rtype); - void *reg_val = NULL; size_t reg_size = KVM_REG_SIZE(reg->id); + void *reg_val; + int rc; - if (rtype == KVM_REG_RISCV_VECTOR && - riscv_isa_extension_available(isa, v)) { - reg_val = kvm_riscv_vcpu_vreg_addr(vcpu, reg_num, reg_size); - } - - if (!reg_val) + if (rtype != KVM_REG_RISCV_VECTOR) return -EINVAL; + if (!riscv_isa_extension_available(isa, v)) + return -ENOENT; + + rc = kvm_riscv_vcpu_vreg_addr(vcpu, reg_num, reg_size, ®_val); + if (rc) + return rc; + if (copy_from_user(reg_val, uaddr, reg_size)) return -EFAULT; -- GitLab From e47f3c2843c2c23467f9447ed977dfccbe13a6f7 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Thu, 3 Aug 2023 13:33:02 -0300 Subject: [PATCH 0919/3445] docs: kvm: riscv: document EBUSY in KVM_SET_ONE_REG The EBUSY errno is being used for KVM_SET_ONE_REG as a way to tell userspace that a given reg can't be changed after the vcpu started. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- Documentation/virt/kvm/api.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index c0ddd3035462b..3249fb56cc696 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -2259,6 +2259,8 @@ Errors: EINVAL invalid register ID, or no such register or used with VMs in protected virtualization mode on s390 EPERM (arm64) register access not allowed before vcpu finalization + EBUSY (riscv) changing register value not allowed after the vcpu + has run at least once ====== ============================================================ (These error codes are indicative only: do not rely on a specific error -- GitLab From 630b4cee9c378e2dbb56ed84f71fc2fac50b716e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 4 Aug 2023 16:56:18 +0300 Subject: [PATCH 0920/3445] RISC-V: KVM: Improve vector save/restore functions Make two nonfunctional changes to the vector get/set vector reg functions and their supporting function for simplification and readability. The first is to not pass KVM_REG_RISCV_VECTOR, but rather integrate it directly into the masking. The second is to rename reg_val to reg_addr where and address is used instead of a value. Also opportunistically touch up some of the code formatting for a third nonfunctional change. Signed-off-by: Andrew Jones Reviewed-by: Daniel Henrique Barboza Signed-off-by: Anup Patel --- arch/riscv/include/asm/kvm_vcpu_vector.h | 6 ++-- arch/riscv/kvm/vcpu_onereg.c | 6 ++-- arch/riscv/kvm/vcpu_vector.c | 46 ++++++++++-------------- 3 files changed, 23 insertions(+), 35 deletions(-) diff --git a/arch/riscv/include/asm/kvm_vcpu_vector.h b/arch/riscv/include/asm/kvm_vcpu_vector.h index ff994fdd6d0d1..27f5bccdd8b02 100644 --- a/arch/riscv/include/asm/kvm_vcpu_vector.h +++ b/arch/riscv/include/asm/kvm_vcpu_vector.h @@ -74,9 +74,7 @@ static inline void kvm_riscv_vcpu_free_vector_context(struct kvm_vcpu *vcpu) #endif int kvm_riscv_vcpu_get_reg_vector(struct kvm_vcpu *vcpu, - const struct kvm_one_reg *reg, - unsigned long rtype); + const struct kvm_one_reg *reg); int kvm_riscv_vcpu_set_reg_vector(struct kvm_vcpu *vcpu, - const struct kvm_one_reg *reg, - unsigned long rtype); + const struct kvm_one_reg *reg); #endif diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index 989ea32dbcbee..9fee1c176fbb7 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -645,8 +645,7 @@ int kvm_riscv_vcpu_set_reg(struct kvm_vcpu *vcpu, case KVM_REG_RISCV_SBI_EXT: return kvm_riscv_vcpu_set_reg_sbi_ext(vcpu, reg); case KVM_REG_RISCV_VECTOR: - return kvm_riscv_vcpu_set_reg_vector(vcpu, reg, - KVM_REG_RISCV_VECTOR); + return kvm_riscv_vcpu_set_reg_vector(vcpu, reg); default: break; } @@ -677,8 +676,7 @@ int kvm_riscv_vcpu_get_reg(struct kvm_vcpu *vcpu, case KVM_REG_RISCV_SBI_EXT: return kvm_riscv_vcpu_get_reg_sbi_ext(vcpu, reg); case KVM_REG_RISCV_VECTOR: - return kvm_riscv_vcpu_get_reg_vector(vcpu, reg, - KVM_REG_RISCV_VECTOR); + return kvm_riscv_vcpu_get_reg_vector(vcpu, reg); default: break; } diff --git a/arch/riscv/kvm/vcpu_vector.c b/arch/riscv/kvm/vcpu_vector.c index 39c5bceb4d1b0..b430cbb695214 100644 --- a/arch/riscv/kvm/vcpu_vector.c +++ b/arch/riscv/kvm/vcpu_vector.c @@ -92,9 +92,9 @@ void kvm_riscv_vcpu_free_vector_context(struct kvm_vcpu *vcpu) #endif static int kvm_riscv_vcpu_vreg_addr(struct kvm_vcpu *vcpu, - unsigned long reg_num, - size_t reg_size, - void **reg_val) + unsigned long reg_num, + size_t reg_size, + void **reg_addr) { struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; size_t vlenb = riscv_v_vsize / 32; @@ -104,16 +104,16 @@ static int kvm_riscv_vcpu_vreg_addr(struct kvm_vcpu *vcpu, return -EINVAL; switch (reg_num) { case KVM_REG_RISCV_VECTOR_CSR_REG(vstart): - *reg_val = &cntx->vector.vstart; + *reg_addr = &cntx->vector.vstart; break; case KVM_REG_RISCV_VECTOR_CSR_REG(vl): - *reg_val = &cntx->vector.vl; + *reg_addr = &cntx->vector.vl; break; case KVM_REG_RISCV_VECTOR_CSR_REG(vtype): - *reg_val = &cntx->vector.vtype; + *reg_addr = &cntx->vector.vtype; break; case KVM_REG_RISCV_VECTOR_CSR_REG(vcsr): - *reg_val = &cntx->vector.vcsr; + *reg_addr = &cntx->vector.vcsr; break; case KVM_REG_RISCV_VECTOR_CSR_REG(datap): default: @@ -122,8 +122,8 @@ static int kvm_riscv_vcpu_vreg_addr(struct kvm_vcpu *vcpu, } else if (reg_num <= KVM_REG_RISCV_VECTOR_REG(31)) { if (reg_size != vlenb) return -EINVAL; - *reg_val = cntx->vector.datap - + (reg_num - KVM_REG_RISCV_VECTOR_REG(0)) * vlenb; + *reg_addr = cntx->vector.datap + + (reg_num - KVM_REG_RISCV_VECTOR_REG(0)) * vlenb; } else { return -ENOENT; } @@ -132,60 +132,52 @@ static int kvm_riscv_vcpu_vreg_addr(struct kvm_vcpu *vcpu, } int kvm_riscv_vcpu_get_reg_vector(struct kvm_vcpu *vcpu, - const struct kvm_one_reg *reg, - unsigned long rtype) + const struct kvm_one_reg *reg) { unsigned long *isa = vcpu->arch.isa; unsigned long __user *uaddr = (unsigned long __user *)(unsigned long)reg->addr; unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | - rtype); + KVM_REG_RISCV_VECTOR); size_t reg_size = KVM_REG_SIZE(reg->id); - void *reg_val; + void *reg_addr; int rc; - if (rtype != KVM_REG_RISCV_VECTOR) - return -EINVAL; - if (!riscv_isa_extension_available(isa, v)) return -ENOENT; - rc = kvm_riscv_vcpu_vreg_addr(vcpu, reg_num, reg_size, ®_val); + rc = kvm_riscv_vcpu_vreg_addr(vcpu, reg_num, reg_size, ®_addr); if (rc) return rc; - if (copy_to_user(uaddr, reg_val, reg_size)) + if (copy_to_user(uaddr, reg_addr, reg_size)) return -EFAULT; return 0; } int kvm_riscv_vcpu_set_reg_vector(struct kvm_vcpu *vcpu, - const struct kvm_one_reg *reg, - unsigned long rtype) + const struct kvm_one_reg *reg) { unsigned long *isa = vcpu->arch.isa; unsigned long __user *uaddr = (unsigned long __user *)(unsigned long)reg->addr; unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | - rtype); + KVM_REG_RISCV_VECTOR); size_t reg_size = KVM_REG_SIZE(reg->id); - void *reg_val; + void *reg_addr; int rc; - if (rtype != KVM_REG_RISCV_VECTOR) - return -EINVAL; - if (!riscv_isa_extension_available(isa, v)) return -ENOENT; - rc = kvm_riscv_vcpu_vreg_addr(vcpu, reg_num, reg_size, ®_val); + rc = kvm_riscv_vcpu_vreg_addr(vcpu, reg_num, reg_size, ®_addr); if (rc) return rc; - if (copy_from_user(reg_val, uaddr, reg_size)) + if (copy_from_user(reg_addr, uaddr, reg_size)) return -EFAULT; return 0; -- GitLab From 224acec66433ee36f58531d815e61498a407ac44 Mon Sep 17 00:00:00 2001 From: Carlos Song Date: Thu, 27 Jul 2023 11:03:47 +0800 Subject: [PATCH 0921/3445] i2c: imx-lpi2c: directly return ISR when detect a NACK A NACK flag in ISR means i2c bus error. In such condition, there is no need to do read/write operation. In this patch, i2c will check MSR_NDF, MSR_RDF and MSR_TDF flag in turn, it's making mutually exclusive NACK/read/write. So when a NACK is received(MSR_NDF), i2c will return ISR directly and then stop i2c transfer. Signed-off-by: Carlos Song Reviewed-by: Andi Shyti Link: https://lore.kernel.org/r/20230727030347.3552992-1-carlos.song@nxp.com Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-imx-lpi2c.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index c3287c887c6fa..636ad32479829 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -514,14 +514,12 @@ static irqreturn_t lpi2c_imx_isr(int irq, void *dev_id) temp = readl(lpi2c_imx->base + LPI2C_MSR); temp &= enabled; - if (temp & MSR_RDF) - lpi2c_imx_read_rxfifo(lpi2c_imx); - - if (temp & MSR_TDF) - lpi2c_imx_write_txfifo(lpi2c_imx); - if (temp & MSR_NDF) complete(&lpi2c_imx->complete); + else if (temp & MSR_RDF) + lpi2c_imx_read_rxfifo(lpi2c_imx); + else if (temp & MSR_TDF) + lpi2c_imx_write_txfifo(lpi2c_imx); return IRQ_HANDLED; } -- GitLab From f9372b9202a443051b9ed9b9cc34a79d44493e1a Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Wed, 26 Jul 2023 17:42:26 +0000 Subject: [PATCH 0922/3445] i2c: s3c2410: Remove redundant dev_err() There is no need to call the dev_err() function directly to print a custom message when handling an error from platform_get_irq() function as it is going to display an appropriate error message in case of a failure. Signed-off-by: Ruan Jinjie Reviewed-by: Andi Shyti Link: https://lore.kernel.org/r/20230726174226.2480552-1-ruanjinjie@huawei.com Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-s3c2410.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 28f0e5c64f32e..703a43446eaa3 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -1076,7 +1076,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (!(i2c->quirks & QUIRK_POLL)) { i2c->irq = ret = platform_get_irq(pdev, 0); if (ret < 0) { - dev_err(&pdev->dev, "cannot find IRQ\n"); clk_unprepare(i2c->clk); return ret; } -- GitLab From 2f0a81a2452f4acfdecbdb5da9f4d2c3606fb7e2 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:50:25 +0200 Subject: [PATCH 0923/3445] i2c: au1550: Remove #ifdef guards for PM related functions Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Note that the behaviour is slightly different than before; the original code wrapped the suspend/resume with #ifdef CONFIG_PM guards, which resulted in these functions being compiled in but never used when CONFIG_PM_SLEEP was disabled. Now, those functions are only compiled in when CONFIG_PM_SLEEP is enabled. Signed-off-by: Paul Cercueil Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230722115046.27323-2-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-au1550.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index e66c12ecf2706..8e43f25c117e6 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c @@ -342,7 +342,6 @@ static void i2c_au1550_remove(struct platform_device *pdev) i2c_au1550_disable(priv); } -#ifdef CONFIG_PM static int i2c_au1550_suspend(struct device *dev) { struct i2c_au1550_data *priv = dev_get_drvdata(dev); @@ -361,21 +360,13 @@ static int i2c_au1550_resume(struct device *dev) return 0; } -static const struct dev_pm_ops i2c_au1550_pmops = { - .suspend = i2c_au1550_suspend, - .resume = i2c_au1550_resume, -}; - -#define AU1XPSC_SMBUS_PMOPS (&i2c_au1550_pmops) - -#else -#define AU1XPSC_SMBUS_PMOPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(i2c_au1550_pmops, + i2c_au1550_suspend, i2c_au1550_resume); static struct platform_driver au1xpsc_smbus_driver = { .driver = { .name = "au1xpsc_smbus", - .pm = AU1XPSC_SMBUS_PMOPS, + .pm = pm_sleep_ptr(&i2c_au1550_pmops), }, .probe = i2c_au1550_probe, .remove_new = i2c_au1550_remove, -- GitLab From 9dc96b7570472aa0d2299c9a696a766e7ca5c830 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:50:26 +0200 Subject: [PATCH 0924/3445] i2c: iproc: Remove #ifdef guards for PM related functions Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Signed-off-by: Paul Cercueil Reviewed-by: Jonathan Cameron Acked-by: Ray Jui Reviewed-by: Florian Fainelli Link: https://lore.kernel.org/r/20230722115046.27323-3-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-bcm-iproc.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index 2d8342fdc25de..8a3e2208475c9 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -1125,8 +1125,6 @@ static void bcm_iproc_i2c_remove(struct platform_device *pdev) bcm_iproc_i2c_enable_disable(iproc_i2c, false); } -#ifdef CONFIG_PM_SLEEP - static int bcm_iproc_i2c_suspend(struct device *dev) { struct bcm_iproc_i2c_dev *iproc_i2c = dev_get_drvdata(dev); @@ -1177,12 +1175,6 @@ static const struct dev_pm_ops bcm_iproc_i2c_pm_ops = { .resume_early = &bcm_iproc_i2c_resume }; -#define BCM_IPROC_I2C_PM_OPS (&bcm_iproc_i2c_pm_ops) -#else -#define BCM_IPROC_I2C_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ - - static int bcm_iproc_i2c_reg_slave(struct i2c_client *slave) { struct bcm_iproc_i2c_dev *iproc_i2c = i2c_get_adapdata(slave->adapter); @@ -1255,7 +1247,7 @@ static struct platform_driver bcm_iproc_i2c_driver = { .driver = { .name = "bcm-iproc-i2c", .of_match_table = bcm_iproc_i2c_of_match, - .pm = BCM_IPROC_I2C_PM_OPS, + .pm = pm_sleep_ptr(&bcm_iproc_i2c_pm_ops), }, .probe = bcm_iproc_i2c_probe, .remove_new = bcm_iproc_i2c_remove, -- GitLab From bb48aa5f6847170f2dab24cfd377759e4d848b5b Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:50:27 +0200 Subject: [PATCH 0925/3445] i2c: brcmstb: Remove #ifdef guards for PM related functions Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Signed-off-by: Paul Cercueil Reviewed-by: Jonathan Cameron Reviewed-by: Florian Fainelli Link: https://lore.kernel.org/r/20230722115046.27323-4-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-brcmstb.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c index cf92cbcb8c86b..c778bcca95fea 100644 --- a/drivers/i2c/busses/i2c-brcmstb.c +++ b/drivers/i2c/busses/i2c-brcmstb.c @@ -697,7 +697,6 @@ static void brcmstb_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&dev->adapter); } -#ifdef CONFIG_PM_SLEEP static int brcmstb_i2c_suspend(struct device *dev) { struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev); @@ -715,10 +714,9 @@ static int brcmstb_i2c_resume(struct device *dev) return 0; } -#endif -static SIMPLE_DEV_PM_OPS(brcmstb_i2c_pm, brcmstb_i2c_suspend, - brcmstb_i2c_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(brcmstb_i2c_pm, brcmstb_i2c_suspend, + brcmstb_i2c_resume); static const struct of_device_id brcmstb_i2c_of_match[] = { {.compatible = "brcm,brcmstb-i2c"}, @@ -732,7 +730,7 @@ static struct platform_driver brcmstb_i2c_driver = { .driver = { .name = "brcmstb-i2c", .of_match_table = brcmstb_i2c_of_match, - .pm = &brcmstb_i2c_pm, + .pm = pm_sleep_ptr(&brcmstb_i2c_pm), }, .probe = brcmstb_i2c_probe, .remove_new = brcmstb_i2c_remove, -- GitLab From a6624009a10beff0525399f2e24641654d56bc06 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:50:28 +0200 Subject: [PATCH 0926/3445] i2c: davinci: Remove #ifdef guards for PM related functions Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Note that the behaviour is slightly different than before; the original code wrapped the suspend/resume with #ifdef CONFIG_PM guards, which resulted in these functions being compiled in but never used when CONFIG_PM_SLEEP was disabled. Now, those functions are only compiled in when CONFIG_PM_SLEEP is enabled. Signed-off-by: Paul Cercueil Reviewed-by: Jonathan Cameron Reviewed-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20230722115046.27323-5-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-davinci.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 71b60778c643d..52527189a7bf6 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -902,7 +902,6 @@ static void davinci_i2c_remove(struct platform_device *pdev) pm_runtime_disable(dev->dev); } -#ifdef CONFIG_PM static int davinci_i2c_suspend(struct device *dev) { struct davinci_i2c_dev *i2c_dev = dev_get_drvdata(dev); @@ -926,15 +925,10 @@ static int davinci_i2c_resume(struct device *dev) static const struct dev_pm_ops davinci_i2c_pm = { .suspend = davinci_i2c_suspend, .resume = davinci_i2c_resume, - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; -#define davinci_i2c_pm_ops (&davinci_i2c_pm) -#else -#define davinci_i2c_pm_ops NULL -#endif - static const struct platform_device_id davinci_i2c_driver_ids[] = { { .name = "i2c_davinci", }, { /* sentinel */ } @@ -947,7 +941,7 @@ static struct platform_driver davinci_i2c_driver = { .id_table = davinci_i2c_driver_ids, .driver = { .name = "i2c_davinci", - .pm = davinci_i2c_pm_ops, + .pm = pm_sleep_ptr(&davinci_i2c_pm), .of_match_table = davinci_i2c_of_match, }, }; -- GitLab From a9e4d8b641bc6cc23113cfc2109a8ff15ac1ae19 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:50:29 +0200 Subject: [PATCH 0927/3445] i2c: designware: Remove #ifdef guards for PM related functions Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Signed-off-by: Paul Cercueil Reviewed-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Acked-by: Jarkko Nikula Link: https://lore.kernel.org/r/20230722115046.27323-6-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-designware-platdrv.c | 22 ++++++--------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 970c1c3b04027..855b698e99c08 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -418,7 +418,6 @@ static void dw_i2c_plat_remove(struct platform_device *pdev) reset_control_assert(dev->rst); } -#ifdef CONFIG_PM_SLEEP static int dw_i2c_plat_prepare(struct device *dev) { /* @@ -429,11 +428,7 @@ static int dw_i2c_plat_prepare(struct device *dev) */ return !has_acpi_companion(dev); } -#else -#define dw_i2c_plat_prepare NULL -#endif -#ifdef CONFIG_PM static int dw_i2c_plat_runtime_suspend(struct device *dev) { struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); @@ -447,7 +442,7 @@ static int dw_i2c_plat_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused dw_i2c_plat_suspend(struct device *dev) +static int dw_i2c_plat_suspend(struct device *dev) { struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); @@ -468,7 +463,7 @@ static int dw_i2c_plat_runtime_resume(struct device *dev) return 0; } -static int __maybe_unused dw_i2c_plat_resume(struct device *dev) +static int dw_i2c_plat_resume(struct device *dev) { struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); @@ -479,16 +474,11 @@ static int __maybe_unused dw_i2c_plat_resume(struct device *dev) } static const struct dev_pm_ops dw_i2c_dev_pm_ops = { - .prepare = dw_i2c_plat_prepare, - SET_LATE_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume) - SET_RUNTIME_PM_OPS(dw_i2c_plat_runtime_suspend, dw_i2c_plat_runtime_resume, NULL) + .prepare = pm_sleep_ptr(dw_i2c_plat_prepare), + LATE_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume) + RUNTIME_PM_OPS(dw_i2c_plat_runtime_suspend, dw_i2c_plat_runtime_resume, NULL) }; -#define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops) -#else -#define DW_I2C_DEV_PMOPS NULL -#endif - /* Work with hotplug and coldplug */ MODULE_ALIAS("platform:i2c_designware"); @@ -499,7 +489,7 @@ static struct platform_driver dw_i2c_driver = { .name = "i2c_designware", .of_match_table = of_match_ptr(dw_i2c_of_match), .acpi_match_table = ACPI_PTR(dw_i2c_acpi_match), - .pm = DW_I2C_DEV_PMOPS, + .pm = pm_ptr(&dw_i2c_dev_pm_ops), }, }; -- GitLab From 375b26c952101aacfd48245809030ee20460e3a0 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:50:30 +0200 Subject: [PATCH 0928/3445] i2c: exynos5: Remove #ifdef guards for PM related functions Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Signed-off-by: Paul Cercueil Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230722115046.27323-7-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-exynos5.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index f378cd479e558..5b201a326c13b 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -892,7 +892,6 @@ static void exynos5_i2c_remove(struct platform_device *pdev) clk_unprepare(i2c->pclk); } -#ifdef CONFIG_PM_SLEEP static int exynos5_i2c_suspend_noirq(struct device *dev) { struct exynos5_i2c *i2c = dev_get_drvdata(dev); @@ -934,11 +933,10 @@ err_pclk: clk_disable_unprepare(i2c->pclk); return ret; } -#endif static const struct dev_pm_ops exynos5_i2c_dev_pm_ops = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos5_i2c_suspend_noirq, - exynos5_i2c_resume_noirq) + NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos5_i2c_suspend_noirq, + exynos5_i2c_resume_noirq) }; static struct platform_driver exynos5_i2c_driver = { @@ -946,7 +944,7 @@ static struct platform_driver exynos5_i2c_driver = { .remove_new = exynos5_i2c_remove, .driver = { .name = "exynos5-hsi2c", - .pm = &exynos5_i2c_dev_pm_ops, + .pm = pm_sleep_ptr(&exynos5_i2c_dev_pm_ops), .of_match_table = exynos5_i2c_match, }, }; -- GitLab From 28f3fb1cd8c57dbb9ba97f674b22954b256298f8 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:50:31 +0200 Subject: [PATCH 0929/3445] i2c: hix5hd2: Remove #ifdef guards for PM related functions Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Note that this driver should probably use the DEFINE_RUNTIME_DEV_PM_OPS() macro, which would allow the devices to be runtime-suspended on system suspend. Signed-off-by: Paul Cercueil Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230722115046.27323-8-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-hix5hd2.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-hix5hd2.c b/drivers/i2c/busses/i2c-hix5hd2.c index 784a5f56eb765..8e75515c3ca47 100644 --- a/drivers/i2c/busses/i2c-hix5hd2.c +++ b/drivers/i2c/busses/i2c-hix5hd2.c @@ -475,7 +475,6 @@ static void hix5hd2_i2c_remove(struct platform_device *pdev) pm_runtime_set_suspended(priv->dev); } -#ifdef CONFIG_PM static int hix5hd2_i2c_runtime_suspend(struct device *dev) { struct hix5hd2_i2c_priv *priv = dev_get_drvdata(dev); @@ -494,12 +493,11 @@ static int hix5hd2_i2c_runtime_resume(struct device *dev) return 0; } -#endif static const struct dev_pm_ops hix5hd2_i2c_pm_ops = { - SET_RUNTIME_PM_OPS(hix5hd2_i2c_runtime_suspend, - hix5hd2_i2c_runtime_resume, - NULL) + RUNTIME_PM_OPS(hix5hd2_i2c_runtime_suspend, + hix5hd2_i2c_runtime_resume, + NULL) }; static const struct of_device_id hix5hd2_i2c_match[] = { @@ -513,7 +511,7 @@ static struct platform_driver hix5hd2_i2c_driver = { .remove_new = hix5hd2_i2c_remove, .driver = { .name = "hix5hd2-i2c", - .pm = &hix5hd2_i2c_pm_ops, + .pm = pm_ptr(&hix5hd2_i2c_pm_ops), .of_match_table = hix5hd2_i2c_match, }, }; -- GitLab From a6273e413a9a781b63cd30a7c976be8d7f71cf5b Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:50:32 +0200 Subject: [PATCH 0930/3445] i2c: i801: Remove #ifdef guards for PM related functions Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Signed-off-by: Paul Cercueil Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230722115046.27323-9-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-i801.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 943b8e6d026da..73ae064321331 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1808,7 +1808,6 @@ static void i801_shutdown(struct pci_dev *dev) pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); } -#ifdef CONFIG_PM_SLEEP static int i801_suspend(struct device *dev) { struct i801_priv *priv = dev_get_drvdata(dev); @@ -1827,9 +1826,8 @@ static int i801_resume(struct device *dev) return 0; } -#endif -static SIMPLE_DEV_PM_OPS(i801_pm_ops, i801_suspend, i801_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(i801_pm_ops, i801_suspend, i801_resume); static struct pci_driver i801_driver = { .name = DRV_NAME, @@ -1838,7 +1836,7 @@ static struct pci_driver i801_driver = { .remove = i801_remove, .shutdown = i801_shutdown, .driver = { - .pm = &i801_pm_ops, + .pm = pm_sleep_ptr(&i801_pm_ops), .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; -- GitLab From 775a3c47413e8b4bc2e956bd9728b6e5c320aa31 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:50:33 +0200 Subject: [PATCH 0931/3445] i2c: img-scb: Remove #ifdef guards for PM related functions Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Signed-off-by: Paul Cercueil Acked-by: Andi Shyti Link: https://lore.kernel.org/r/20230722115046.27323-10-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-img-scb.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c index 66ba36949ab59..f9d4bfef511c3 100644 --- a/drivers/i2c/busses/i2c-img-scb.c +++ b/drivers/i2c/busses/i2c-img-scb.c @@ -1454,7 +1454,6 @@ static int img_i2c_runtime_resume(struct device *dev) return 0; } -#ifdef CONFIG_PM_SLEEP static int img_i2c_suspend(struct device *dev) { struct img_i2c *i2c = dev_get_drvdata(dev); @@ -1482,13 +1481,10 @@ static int img_i2c_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops img_i2c_pm = { - SET_RUNTIME_PM_OPS(img_i2c_runtime_suspend, - img_i2c_runtime_resume, - NULL) - SET_SYSTEM_SLEEP_PM_OPS(img_i2c_suspend, img_i2c_resume) + RUNTIME_PM_OPS(img_i2c_runtime_suspend, img_i2c_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(img_i2c_suspend, img_i2c_resume) }; static const struct of_device_id img_scb_i2c_match[] = { @@ -1501,7 +1497,7 @@ static struct platform_driver img_scb_i2c_driver = { .driver = { .name = "img-i2c-scb", .of_match_table = img_scb_i2c_match, - .pm = &img_i2c_pm, + .pm = pm_ptr(&img_i2c_pm), }, .probe = img_i2c_probe, .remove_new = img_i2c_remove, -- GitLab From 2e4ff22b60f7c21c14c6cc09f0b5cea54b62ce12 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:50:34 +0200 Subject: [PATCH 0932/3445] i2c: kempld: Convert to use regular device PM Provide PM callbacks through platform_driver.driver.pm instead of platform_driver.{suspend,resume} as any good-behaved driver should do. Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Signed-off-by: Paul Cercueil Acked-by: Andi Shyti Link: https://lore.kernel.org/r/20230722115046.27323-11-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-kempld.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/i2c/busses/i2c-kempld.c b/drivers/i2c/busses/i2c-kempld.c index 281058e3ea463..e01d753082884 100644 --- a/drivers/i2c/busses/i2c-kempld.c +++ b/drivers/i2c/busses/i2c-kempld.c @@ -350,10 +350,9 @@ static void kempld_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&i2c->adap); } -#ifdef CONFIG_PM -static int kempld_i2c_suspend(struct platform_device *pdev, pm_message_t state) +static int kempld_i2c_suspend(struct device *dev) { - struct kempld_i2c_data *i2c = platform_get_drvdata(pdev); + struct kempld_i2c_data *i2c = dev_get_drvdata(dev); struct kempld_device_data *pld = i2c->pld; u8 ctrl; @@ -366,9 +365,9 @@ static int kempld_i2c_suspend(struct platform_device *pdev, pm_message_t state) return 0; } -static int kempld_i2c_resume(struct platform_device *pdev) +static int kempld_i2c_resume(struct device *dev) { - struct kempld_i2c_data *i2c = platform_get_drvdata(pdev); + struct kempld_i2c_data *i2c = dev_get_drvdata(dev); struct kempld_device_data *pld = i2c->pld; kempld_get_mutex(pld); @@ -377,19 +376,17 @@ static int kempld_i2c_resume(struct platform_device *pdev) return 0; } -#else -#define kempld_i2c_suspend NULL -#define kempld_i2c_resume NULL -#endif + +static DEFINE_SIMPLE_DEV_PM_OPS(kempld_i2c_pm_ops, + kempld_i2c_suspend, kempld_i2c_resume); static struct platform_driver kempld_i2c_driver = { .driver = { .name = "kempld-i2c", + .pm = pm_sleep_ptr(&kempld_i2c_pm_ops), }, .probe = kempld_i2c_probe, .remove_new = kempld_i2c_remove, - .suspend = kempld_i2c_suspend, - .resume = kempld_i2c_resume, }; module_platform_driver(kempld_i2c_driver); -- GitLab From 9f38edaf4a005a2f435aa5e5ad8ee2e9fc4e3379 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:50:35 +0200 Subject: [PATCH 0933/3445] i2c: lpc2k: Remove #ifdef guards for PM related functions Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Note that the behaviour is slightly different than before; the original code wrapped the suspend/resume with #ifdef CONFIG_PM guards, which resulted in these functions being compiled in but never used when CONFIG_PM_SLEEP was disabled. Now, those functions are only compiled in when CONFIG_PM_SLEEP is enabled. Signed-off-by: Paul Cercueil Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230722115046.27323-12-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-lpc2k.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-lpc2k.c b/drivers/i2c/busses/i2c-lpc2k.c index 5c6d965547539..c61157f1409b3 100644 --- a/drivers/i2c/busses/i2c-lpc2k.c +++ b/drivers/i2c/busses/i2c-lpc2k.c @@ -431,7 +431,6 @@ static void i2c_lpc2k_remove(struct platform_device *dev) i2c_del_adapter(&i2c->adap); } -#ifdef CONFIG_PM static int i2c_lpc2k_suspend(struct device *dev) { struct lpc2k_i2c *i2c = dev_get_drvdata(dev); @@ -456,11 +455,6 @@ static const struct dev_pm_ops i2c_lpc2k_dev_pm_ops = { .resume_noirq = i2c_lpc2k_resume, }; -#define I2C_LPC2K_DEV_PM_OPS (&i2c_lpc2k_dev_pm_ops) -#else -#define I2C_LPC2K_DEV_PM_OPS NULL -#endif - static const struct of_device_id lpc2k_i2c_match[] = { { .compatible = "nxp,lpc1788-i2c" }, {}, @@ -472,7 +466,7 @@ static struct platform_driver i2c_lpc2k_driver = { .remove_new = i2c_lpc2k_remove, .driver = { .name = "lpc2k-i2c", - .pm = I2C_LPC2K_DEV_PM_OPS, + .pm = pm_sleep_ptr(&i2c_lpc2k_dev_pm_ops), .of_match_table = lpc2k_i2c_match, }, }; -- GitLab From ba733668dc38610bbd6031a9745e9f93c8bbcd74 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:50:36 +0200 Subject: [PATCH 0934/3445] i2c: mt65xx: Remove #ifdef guards for PM related functions Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Signed-off-by: Paul Cercueil Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230722115046.27323-13-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-mt65xx.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c index 7ca3f2221ba69..21cc39e35cf61 100644 --- a/drivers/i2c/busses/i2c-mt65xx.c +++ b/drivers/i2c/busses/i2c-mt65xx.c @@ -1514,7 +1514,6 @@ static void mtk_i2c_remove(struct platform_device *pdev) clk_bulk_unprepare(I2C_MT65XX_CLK_MAX, i2c->clocks); } -#ifdef CONFIG_PM_SLEEP static int mtk_i2c_suspend_noirq(struct device *dev) { struct mtk_i2c *i2c = dev_get_drvdata(dev); @@ -1544,11 +1543,10 @@ static int mtk_i2c_resume_noirq(struct device *dev) return 0; } -#endif static const struct dev_pm_ops mtk_i2c_pm = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_i2c_suspend_noirq, - mtk_i2c_resume_noirq) + NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_i2c_suspend_noirq, + mtk_i2c_resume_noirq) }; static struct platform_driver mtk_i2c_driver = { @@ -1556,7 +1554,7 @@ static struct platform_driver mtk_i2c_driver = { .remove_new = mtk_i2c_remove, .driver = { .name = I2C_DRV_NAME, - .pm = &mtk_i2c_pm, + .pm = pm_sleep_ptr(&mtk_i2c_pm), .of_match_table = mtk_i2c_of_match, }, }; -- GitLab From e159fe0d0c44d4530e85d179682f25af1a8aee4c Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:50:37 +0200 Subject: [PATCH 0935/3445] i2c: nomadik: Remove #ifdef guards for PM related functions Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Signed-off-by: Paul Cercueil Reviewed-by: Jonathan Cameron Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20230722115046.27323-14-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-nomadik.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 212f412f1c749..b10574d42b7ac 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -873,7 +873,6 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) return IRQ_HANDLED; } -#ifdef CONFIG_PM_SLEEP static int nmk_i2c_suspend_late(struct device *dev) { int ret; @@ -890,9 +889,7 @@ static int nmk_i2c_resume_early(struct device *dev) { return pm_runtime_force_resume(dev); } -#endif -#ifdef CONFIG_PM static int nmk_i2c_runtime_suspend(struct device *dev) { struct amba_device *adev = to_amba_device(dev); @@ -925,13 +922,10 @@ static int nmk_i2c_runtime_resume(struct device *dev) return ret; } -#endif static const struct dev_pm_ops nmk_i2c_pm = { - SET_LATE_SYSTEM_SLEEP_PM_OPS(nmk_i2c_suspend_late, nmk_i2c_resume_early) - SET_RUNTIME_PM_OPS(nmk_i2c_runtime_suspend, - nmk_i2c_runtime_resume, - NULL) + LATE_SYSTEM_SLEEP_PM_OPS(nmk_i2c_suspend_late, nmk_i2c_resume_early) + RUNTIME_PM_OPS(nmk_i2c_runtime_suspend, nmk_i2c_runtime_resume, NULL) }; static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap) @@ -1078,7 +1072,7 @@ static struct amba_driver nmk_i2c_driver = { .drv = { .owner = THIS_MODULE, .name = DRIVER_NAME, - .pm = &nmk_i2c_pm, + .pm = pm_ptr(&nmk_i2c_pm), }, .id_table = nmk_i2c_ids, .probe = nmk_i2c_probe, -- GitLab From 0ad93449b043a446e40713a5e42f0329e6fb0b9c Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:50:38 +0200 Subject: [PATCH 0936/3445] i2c: ocores: Remove #ifdef guards for PM related functions Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Signed-off-by: Paul Cercueil Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230722115046.27323-15-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-ocores.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 4ac77e57bbbfe..041a76f71a49c 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -743,7 +743,6 @@ static void ocores_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&i2c->adap); } -#ifdef CONFIG_PM_SLEEP static int ocores_i2c_suspend(struct device *dev) { struct ocores_i2c *i2c = dev_get_drvdata(dev); @@ -772,11 +771,8 @@ static int ocores_i2c_resume(struct device *dev) return ocores_init(dev, i2c); } -static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume); -#define OCORES_I2C_PM (&ocores_i2c_pm) -#else -#define OCORES_I2C_PM NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(ocores_i2c_pm, + ocores_i2c_suspend, ocores_i2c_resume); static struct platform_driver ocores_i2c_driver = { .probe = ocores_i2c_probe, @@ -784,7 +780,7 @@ static struct platform_driver ocores_i2c_driver = { .driver = { .name = "ocores-i2c", .of_match_table = ocores_i2c_match, - .pm = OCORES_I2C_PM, + .pm = pm_sleep_ptr(&ocores_i2c_pm), }, }; -- GitLab From 6184f92fb16171285872b12c81ca1310d4dda083 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:50:39 +0200 Subject: [PATCH 0937/3445] i2c: pnx: Remove #ifdef guards for PM related functions Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Signed-off-by: Paul Cercueil Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230722115046.27323-16-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-pnx.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 82400057f810a..4ee7db512333d 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -613,7 +613,6 @@ static const struct i2c_algorithm pnx_algorithm = { .functionality = i2c_pnx_func, }; -#ifdef CONFIG_PM_SLEEP static int i2c_pnx_controller_suspend(struct device *dev) { struct i2c_pnx_algo_data *alg_data = dev_get_drvdata(dev); @@ -630,12 +629,9 @@ static int i2c_pnx_controller_resume(struct device *dev) return clk_prepare_enable(alg_data->clk); } -static SIMPLE_DEV_PM_OPS(i2c_pnx_pm, - i2c_pnx_controller_suspend, i2c_pnx_controller_resume); -#define PNX_I2C_PM (&i2c_pnx_pm) -#else -#define PNX_I2C_PM NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(i2c_pnx_pm, + i2c_pnx_controller_suspend, + i2c_pnx_controller_resume); static int i2c_pnx_probe(struct platform_device *pdev) { @@ -763,7 +759,7 @@ static struct platform_driver i2c_pnx_driver = { .driver = { .name = "pnx-i2c", .of_match_table = of_match_ptr(i2c_pnx_of_match), - .pm = PNX_I2C_PM, + .pm = pm_sleep_ptr(&i2c_pnx_pm), }, .probe = i2c_pnx_probe, .remove_new = i2c_pnx_remove, -- GitLab From 1ea4e6b56e672ca6a21bb455f7a1dac141c555f3 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:50:40 +0200 Subject: [PATCH 0938/3445] i2c: pxa: Remove #ifdef guards for PM related functions Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Note that the behaviour is slightly different than before; the original code wrapped the suspend/resume with #ifdef CONFIG_PM guards, which resulted in these functions being compiled in but never used when CONFIG_PM_SLEEP was disabled. Now, those functions are only compiled in when CONFIG_PM_SLEEP is enabled. Signed-off-by: Paul Cercueil Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230722115046.27323-17-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-pxa.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 937f7eebe9067..65a18d73be5c5 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1491,7 +1491,6 @@ static void i2c_pxa_remove(struct platform_device *dev) clk_disable_unprepare(i2c->clk); } -#ifdef CONFIG_PM static int i2c_pxa_suspend_noirq(struct device *dev) { struct pxa_i2c *i2c = dev_get_drvdata(dev); @@ -1516,17 +1515,12 @@ static const struct dev_pm_ops i2c_pxa_dev_pm_ops = { .resume_noirq = i2c_pxa_resume_noirq, }; -#define I2C_PXA_DEV_PM_OPS (&i2c_pxa_dev_pm_ops) -#else -#define I2C_PXA_DEV_PM_OPS NULL -#endif - static struct platform_driver i2c_pxa_driver = { .probe = i2c_pxa_probe, .remove_new = i2c_pxa_remove, .driver = { .name = "pxa2xx-i2c", - .pm = I2C_PXA_DEV_PM_OPS, + .pm = pm_sleep_ptr(&i2c_pxa_dev_pm_ops), .of_match_table = i2c_pxa_dt_ids, }, .id_table = i2c_pxa_id_table, -- GitLab From d19941ac22760daac82ae439b709b5f90ec9e1bb Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:53:05 +0200 Subject: [PATCH 0939/3445] i2c: qup: Remove #ifdef guards for PM related functions Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Note that the driver should probably use the DEFINE_RUNTIME_DEV_PM_OPS() macro, as the system suspend/resume callbacks seem to not do anything more than triggering the runtime-PM states. Signed-off-by: Paul Cercueil Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230722115310.27681-1-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-qup.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index ae90170023b00..598102d16677a 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -1927,7 +1927,6 @@ static void qup_i2c_remove(struct platform_device *pdev) pm_runtime_set_suspended(qup->dev); } -#ifdef CONFIG_PM static int qup_i2c_pm_suspend_runtime(struct device *device) { struct qup_i2c_dev *qup = dev_get_drvdata(device); @@ -1945,9 +1944,7 @@ static int qup_i2c_pm_resume_runtime(struct device *device) qup_i2c_enable_clocks(qup); return 0; } -#endif -#ifdef CONFIG_PM_SLEEP static int qup_i2c_suspend(struct device *device) { if (!pm_runtime_suspended(device)) @@ -1962,16 +1959,11 @@ static int qup_i2c_resume(struct device *device) pm_request_autosuspend(device); return 0; } -#endif static const struct dev_pm_ops qup_i2c_qup_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS( - qup_i2c_suspend, - qup_i2c_resume) - SET_RUNTIME_PM_OPS( - qup_i2c_pm_suspend_runtime, - qup_i2c_pm_resume_runtime, - NULL) + SYSTEM_SLEEP_PM_OPS(qup_i2c_suspend, qup_i2c_resume) + RUNTIME_PM_OPS(qup_i2c_pm_suspend_runtime, + qup_i2c_pm_resume_runtime, NULL) }; static const struct of_device_id qup_i2c_dt_match[] = { @@ -1987,7 +1979,7 @@ static struct platform_driver qup_i2c_driver = { .remove_new = qup_i2c_remove, .driver = { .name = "i2c_qup", - .pm = &qup_i2c_qup_pm_ops, + .pm = pm_ptr(&qup_i2c_qup_pm_ops), .of_match_table = qup_i2c_dt_match, .acpi_match_table = ACPI_PTR(qup_i2c_acpi_match), }, -- GitLab From 941b99ac57facbc6bed99c06592d5471a9bf61cb Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:53:06 +0200 Subject: [PATCH 0940/3445] i2c: rcar: Remove #ifdef guards for PM related functions Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Signed-off-by: Paul Cercueil Reviewed-by: Jonathan Cameron Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230722115310.27681-2-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-rcar.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 2d9c37410ebd0..6b7f0f27d0c3c 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -1169,7 +1169,6 @@ static void rcar_i2c_remove(struct platform_device *pdev) pm_runtime_disable(dev); } -#ifdef CONFIG_PM_SLEEP static int rcar_i2c_suspend(struct device *dev) { struct rcar_i2c_priv *priv = dev_get_drvdata(dev); @@ -1187,19 +1186,14 @@ static int rcar_i2c_resume(struct device *dev) } static const struct dev_pm_ops rcar_i2c_pm_ops = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rcar_i2c_suspend, rcar_i2c_resume) + NOIRQ_SYSTEM_SLEEP_PM_OPS(rcar_i2c_suspend, rcar_i2c_resume) }; -#define DEV_PM_OPS (&rcar_i2c_pm_ops) -#else -#define DEV_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ - static struct platform_driver rcar_i2c_driver = { .driver = { .name = "i2c-rcar", .of_match_table = rcar_i2c_dt_ids, - .pm = DEV_PM_OPS, + .pm = pm_sleep_ptr(&rcar_i2c_pm_ops), }, .probe = rcar_i2c_probe, .remove_new = rcar_i2c_remove, -- GitLab From 67cd435186cc1941d616774765aae0f3e46f1b17 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:53:07 +0200 Subject: [PATCH 0941/3445] i2c: s3c2410: Remove #ifdef guards for PM related functions Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Signed-off-by: Paul Cercueil Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230722115310.27681-3-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-s3c2410.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 703a43446eaa3..92f0cb4df1795 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -1124,7 +1124,6 @@ static void s3c24xx_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&i2c->adap); } -#ifdef CONFIG_PM_SLEEP static int s3c24xx_i2c_suspend_noirq(struct device *dev) { struct s3c24xx_i2c *i2c = dev_get_drvdata(dev); @@ -1154,26 +1153,19 @@ static int s3c24xx_i2c_resume_noirq(struct device *dev) return 0; } -#endif -#ifdef CONFIG_PM static const struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(s3c24xx_i2c_suspend_noirq, - s3c24xx_i2c_resume_noirq) + NOIRQ_SYSTEM_SLEEP_PM_OPS(s3c24xx_i2c_suspend_noirq, + s3c24xx_i2c_resume_noirq) }; -#define S3C24XX_DEV_PM_OPS (&s3c24xx_i2c_dev_pm_ops) -#else -#define S3C24XX_DEV_PM_OPS NULL -#endif - static struct platform_driver s3c24xx_i2c_driver = { .probe = s3c24xx_i2c_probe, .remove_new = s3c24xx_i2c_remove, .id_table = s3c24xx_driver_ids, .driver = { .name = "s3c-i2c", - .pm = S3C24XX_DEV_PM_OPS, + .pm = pm_sleep_ptr(&s3c24xx_i2c_dev_pm_ops), .of_match_table = of_match_ptr(s3c24xx_i2c_match), }, }; -- GitLab From 426b67422b9d2ff38fdb71d443838d2b477c8b21 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:53:08 +0200 Subject: [PATCH 0942/3445] i2c: sh-mobile: Remove #ifdef guards for PM related functions Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Signed-off-by: Paul Cercueil Reviewed-by: Jonathan Cameron Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230722115310.27681-4-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-sh_mobile.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 21717b943a9e0..324407196a10e 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -965,7 +965,6 @@ static void sh_mobile_i2c_remove(struct platform_device *dev) pm_runtime_disable(&dev->dev); } -#ifdef CONFIG_PM_SLEEP static int sh_mobile_i2c_suspend(struct device *dev) { struct sh_mobile_i2c_data *pd = dev_get_drvdata(dev); @@ -983,20 +982,15 @@ static int sh_mobile_i2c_resume(struct device *dev) } static const struct dev_pm_ops sh_mobile_i2c_pm_ops = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sh_mobile_i2c_suspend, - sh_mobile_i2c_resume) + NOIRQ_SYSTEM_SLEEP_PM_OPS(sh_mobile_i2c_suspend, + sh_mobile_i2c_resume) }; -#define DEV_PM_OPS (&sh_mobile_i2c_pm_ops) -#else -#define DEV_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ - static struct platform_driver sh_mobile_i2c_driver = { .driver = { .name = "i2c-sh_mobile", .of_match_table = sh_mobile_i2c_dt_ids, - .pm = DEV_PM_OPS, + .pm = pm_sleep_ptr(&sh_mobile_i2c_pm_ops), }, .probe = sh_mobile_i2c_probe, .remove_new = sh_mobile_i2c_remove, -- GitLab From b221df9c4e09eecd611c290ba3b992e58179f56e Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:53:09 +0200 Subject: [PATCH 0943/3445] i2c: virtio: Remove #ifdef guards for PM related functions Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Signed-off-by: Paul Cercueil Reviewed-by: Jonathan Cameron Acked-by: Viresh Kumar Link: https://lore.kernel.org/r/20230722115310.27681-5-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-virtio.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-virtio.c b/drivers/i2c/busses/i2c-virtio.c index 4b9536f508006..c60ae531ba57c 100644 --- a/drivers/i2c/busses/i2c-virtio.c +++ b/drivers/i2c/busses/i2c-virtio.c @@ -243,7 +243,6 @@ static struct virtio_device_id id_table[] = { }; MODULE_DEVICE_TABLE(virtio, id_table); -#ifdef CONFIG_PM_SLEEP static int virtio_i2c_freeze(struct virtio_device *vdev) { virtio_i2c_del_vqs(vdev); @@ -254,7 +253,6 @@ static int virtio_i2c_restore(struct virtio_device *vdev) { return virtio_i2c_setup_vqs(vdev->priv); } -#endif static const unsigned int features[] = { VIRTIO_I2C_F_ZERO_LENGTH_REQUEST, @@ -269,10 +267,8 @@ static struct virtio_driver virtio_i2c_driver = { .driver = { .name = "i2c_virtio", }, -#ifdef CONFIG_PM_SLEEP - .freeze = virtio_i2c_freeze, - .restore = virtio_i2c_restore, -#endif + .freeze = pm_sleep_ptr(virtio_i2c_freeze), + .restore = pm_sleep_ptr(virtio_i2c_restore), }; module_virtio_driver(virtio_i2c_driver); -- GitLab From ea738c06a9d249f08d0cb49ccec90f611b81d1cc Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 22 Jul 2023 13:53:10 +0200 Subject: [PATCH 0944/3445] i2c: mux: pca954x: Remove #ifdef guards for PM related functions Use the new PM macros for the suspend and resume functions to be automatically dropped by the compiler when CONFIG_PM or CONFIG_PM_SLEEP are disabled, without having to use #ifdef guards. This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch. Signed-off-by: Paul Cercueil Reviewed-by: Jonathan Cameron Acked-by: Peter Rosin Link: https://lore.kernel.org/r/20230722115310.27681-6-paul@crapouillou.net Signed-off-by: Andi Shyti --- drivers/i2c/muxes/i2c-mux-pca954x.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 0ccee2ae57204..6965bf4c2348f 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -530,7 +530,6 @@ static void pca954x_remove(struct i2c_client *client) pca954x_cleanup(muxc); } -#ifdef CONFIG_PM_SLEEP static int pca954x_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -544,14 +543,13 @@ static int pca954x_resume(struct device *dev) return ret; } -#endif -static SIMPLE_DEV_PM_OPS(pca954x_pm, NULL, pca954x_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(pca954x_pm, NULL, pca954x_resume); static struct i2c_driver pca954x_driver = { .driver = { .name = "pca954x", - .pm = &pca954x_pm, + .pm = pm_sleep_ptr(&pca954x_pm), .of_match_table = pca954x_of_match, }, .probe = pca954x_probe, -- GitLab From 54e73cd52250adeba836cd3afef3658b48ae8dc9 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 1 Aug 2023 12:58:15 +0200 Subject: [PATCH 0945/3445] virtio: Remove PM #ifdef guards to fix i2c driver A cleanup in the virtio i2c caused a build failure: drivers/i2c/busses/i2c-virtio.c:270:10: error: 'struct virtio_driver' has no member named 'freeze' drivers/i2c/busses/i2c-virtio.c:271:10: error: 'struct virtio_driver' has no member named 'restore' Change the structure definition to allow this cleanup to be applied everywhere. Fixes: 73d546c76235b ("i2c: virtio: Remove #ifdef guards for PM related functions") Signed-off-by: Arnd Bergmann Reviewed-by: Paul Cercueil Reviewed-by: Andi Shyti Link: https://lore.kernel.org/r/20230801105846.3708252-1-arnd@kernel.org Signed-off-by: Andi Shyti --- include/linux/virtio.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/virtio.h b/include/linux/virtio.h index de6041deee372..7ed071b5ef07e 100644 --- a/include/linux/virtio.h +++ b/include/linux/virtio.h @@ -184,10 +184,8 @@ struct virtio_driver { void (*scan)(struct virtio_device *dev); void (*remove)(struct virtio_device *dev); void (*config_changed)(struct virtio_device *dev); -#ifdef CONFIG_PM int (*freeze)(struct virtio_device *dev); int (*restore)(struct virtio_device *dev); -#endif }; static inline struct virtio_driver *drv_to_virtio(struct device_driver *drv) -- GitLab From f5d5bc5fda5cfc127d258166e5d6d91cf17efd48 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 25 Jul 2023 09:50:55 +0300 Subject: [PATCH 0946/3445] i2c: imx: Clean up a call to request_irq() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is passing a NULL thread to request_threaded_irq(). So it's not really a threaded IRQ at all. It's more readable to call request_irq() instead. Signed-off-by: Dan Carpenter Reviewed-by: Uwe Kleine-König Link: https://lore.kernel.org/r/fa375cc0-893a-4e64-8bf6-cc37f9ebecf5@moroto.mountain Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-imx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 65128a73e8a32..c0cac5bcfdd1c 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -1506,8 +1506,7 @@ static int i2c_imx_probe(struct platform_device *pdev) goto rpm_disable; /* Request IRQ */ - ret = request_threaded_irq(irq, i2c_imx_isr, NULL, IRQF_SHARED, - pdev->name, i2c_imx); + ret = request_irq(irq, i2c_imx_isr, IRQF_SHARED, pdev->name, i2c_imx); if (ret) { dev_err(&pdev->dev, "can't claim irq %d\n", irq); goto rpm_disable; -- GitLab From adcf6eae6d21f480c6d4d691e8dfa5a5223d71c6 Mon Sep 17 00:00:00 2001 From: Zhu Wang Date: Tue, 1 Aug 2023 21:48:14 +0800 Subject: [PATCH 0947/3445] i2c: remove redundant dev_err_probe() When platform_get_irq() is called, the error message has been printed, so it need not to call dev_err_probe() to print error. As the comment of platform_get_irq() says, it returned non-zero value when it succeeded, and it returned negative value when it failed. Signed-off-by: Zhu Wang Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20230801134814.247782-1-wangzhu9@huawei.com Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-davinci.c | 2 +- drivers/i2c/busses/i2c-microchip-corei2c.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 52527189a7bf6..329c952d50627 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -765,7 +765,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) - return dev_err_probe(&pdev->dev, irq, "can't get irq resource\n"); + return irq; dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) diff --git a/drivers/i2c/busses/i2c-microchip-corei2c.c b/drivers/i2c/busses/i2c-microchip-corei2c.c index 7f58f7eaabb63..0b0a1c4d17cae 100644 --- a/drivers/i2c/busses/i2c-microchip-corei2c.c +++ b/drivers/i2c/busses/i2c-microchip-corei2c.c @@ -378,9 +378,8 @@ static int mchp_corei2c_probe(struct platform_device *pdev) return PTR_ERR(idev->base); irq = platform_get_irq(pdev, 0); - if (irq <= 0) - return dev_err_probe(&pdev->dev, -ENXIO, - "invalid IRQ %d for I2C controller\n", irq); + if (irq < 0) + return irq; idev->i2c_clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(idev->i2c_clk)) -- GitLab From 4f68ead61b0a20a37a2b3bc3dda3e7f10a86fd9a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 31 Jul 2023 18:38:32 +0200 Subject: [PATCH 0948/3445] dt-bindings: i2c: nxp,pca9541: convert to DT schema Convert the bindings for NXP PCA9541 I2C bus master selector to DT schema. Reviewed-by: Conor Dooley Acked-by: Peter Rosin Acked-by: Andi Shyti Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230731163833.319258-1-krzysztof.kozlowski@linaro.org Signed-off-by: Andi Shyti --- .../devicetree/bindings/i2c/nxp,pca9541.txt | 29 ---------- .../devicetree/bindings/i2c/nxp,pca9541.yaml | 56 +++++++++++++++++++ 2 files changed, 56 insertions(+), 29 deletions(-) delete mode 100644 Documentation/devicetree/bindings/i2c/nxp,pca9541.txt create mode 100644 Documentation/devicetree/bindings/i2c/nxp,pca9541.yaml diff --git a/Documentation/devicetree/bindings/i2c/nxp,pca9541.txt b/Documentation/devicetree/bindings/i2c/nxp,pca9541.txt deleted file mode 100644 index 42bfc09c8918d..0000000000000 --- a/Documentation/devicetree/bindings/i2c/nxp,pca9541.txt +++ /dev/null @@ -1,29 +0,0 @@ -* NXP PCA9541 I2C bus master selector - -Required Properties: - - - compatible: Must be "nxp,pca9541" - - - reg: The I2C address of the device. - - The following required properties are defined externally: - - - I2C arbitration bus node. See i2c-arb.txt in this directory. - - -Example: - - i2c-arbitrator@74 { - compatible = "nxp,pca9541"; - reg = <0x74>; - - i2c-arb { - #address-cells = <1>; - #size-cells = <0>; - - eeprom@54 { - compatible = "atmel,24c08"; - reg = <0x54>; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/i2c/nxp,pca9541.yaml b/Documentation/devicetree/bindings/i2c/nxp,pca9541.yaml new file mode 100644 index 0000000000000..b65c25c1a435e --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/nxp,pca9541.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/i2c/nxp,pca9541.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP PCA9541 I2C bus master selector + +maintainers: + - Peter Rosin + +properties: + compatible: + const: nxp,pca9541 + + reg: + maxItems: 1 + + i2c-arb: + type: object + $ref: /schemas/i2c/i2c-controller.yaml + unevaluatedProperties: false + description: + I2C arbitration bus node. + +required: + - compatible + - reg + - i2c-arb + +additionalProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + i2c-arbitrator@74 { + compatible = "nxp,pca9541"; + reg = <0x74>; + + i2c-arb { + #address-cells = <1>; + #size-cells = <0>; + + eeprom@54 { + compatible = "atmel,24c08"; + reg = <0x54>; + }; + }; + }; + }; -- GitLab From 5578e75140ea22606b24c19c8b174992f90fb8e7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 31 Jul 2023 18:38:33 +0200 Subject: [PATCH 0949/3445] dt-bindings: i2c: arb-gpio-challange: convert to DT schema Convert the bindings for GPIO-based I2C Arbitration Using a Challenge & Response Mechanism to DT schema. Signed-off-by: Krzysztof Kozlowski Acked-by: Douglas Anderson Link: https://lore.kernel.org/r/20230731163833.319258-2-krzysztof.kozlowski@linaro.org Signed-off-by: Andi Shyti --- .../bindings/i2c/i2c-arb-gpio-challenge.txt | 82 ----------- .../bindings/i2c/i2c-arb-gpio-challenge.yaml | 135 ++++++++++++++++++ .../devicetree/bindings/i2c/i2c-arb.txt | 35 ----- 3 files changed, 135 insertions(+), 117 deletions(-) delete mode 100644 Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt create mode 100644 Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.yaml delete mode 100644 Documentation/devicetree/bindings/i2c/i2c-arb.txt diff --git a/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt b/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt deleted file mode 100644 index 548a73cde796f..0000000000000 --- a/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt +++ /dev/null @@ -1,82 +0,0 @@ -GPIO-based I2C Arbitration Using a Challenge & Response Mechanism -================================================================= -This uses GPIO lines and a challenge & response mechanism to arbitrate who is -the master of an I2C bus in a multimaster situation. - -In many cases using GPIOs to arbitrate is not needed and a design can use -the standard I2C multi-master rules. Using GPIOs is generally useful in -the case where there is a device on the bus that has errata and/or bugs -that makes standard multimaster mode not feasible. - -Note that this scheme works well enough but has some downsides: -* It is nonstandard (not using standard I2C multimaster) -* Having two masters on a bus in general makes it relatively hard to debug - problems (hard to tell if i2c issues were caused by one master, another, or - some device on the bus). - - -Algorithm: - -All masters on the bus have a 'bus claim' line which is an output that the -others can see. These are all active low with pull-ups enabled. We'll -describe these lines as: - -- OUR_CLAIM: output from us signaling to other hosts that we want the bus -- THEIR_CLAIMS: output from others signaling that they want the bus - -The basic algorithm is to assert your line when you want the bus, then make -sure that the other side doesn't want it also. A detailed explanation is best -done with an example. - -Let's say we want to claim the bus. We: -1. Assert OUR_CLAIM. -2. Waits a little bit for the other sides to notice (slew time, say 10 - microseconds). -3. Check THEIR_CLAIMS. If none are asserted then the we have the bus and we are - done. -4. Otherwise, wait for a few milliseconds and see if THEIR_CLAIMS are released. -5. If not, back off, release the claim and wait for a few more milliseconds. -6. Go back to 1 (until retry time has expired). - - -Required properties: -- compatible: i2c-arb-gpio-challenge -- our-claim-gpio: The GPIO that we use to claim the bus. -- their-claim-gpios: The GPIOs that the other sides use to claim the bus. - Note that some implementations may only support a single other master. -- I2C arbitration bus node. See i2c-arb.txt in this directory. - -Optional properties: -- slew-delay-us: microseconds to wait for a GPIO to go high. Default is 10 us. -- wait-retry-us: we'll attempt another claim after this many microseconds. - Default is 3000 us. -- wait-free-us: we'll give up after this many microseconds. Default is 50000 us. - - -Example: - i2c@12ca0000 { - compatible = "acme,some-i2c-device"; - #address-cells = <1>; - #size-cells = <0>; - }; - - i2c-arbitrator { - compatible = "i2c-arb-gpio-challenge"; - - i2c-parent = <&{/i2c@12CA0000}>; - - our-claim-gpio = <&gpf0 3 1>; - their-claim-gpios = <&gpe0 4 1>; - slew-delay-us = <10>; - wait-retry-us = <3000>; - wait-free-us = <50000>; - - i2c-arb { - #address-cells = <1>; - #size-cells = <0>; - - i2c@52 { - // Normal I2C device - }; - }; - }; diff --git a/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.yaml b/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.yaml new file mode 100644 index 0000000000000..b618b5a3433ab --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.yaml @@ -0,0 +1,135 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/i2c/i2c-arb-gpio-challenge.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: GPIO-based I2C Arbitration Using a Challenge & Response Mechanism + +maintainers: + - Doug Anderson + - Peter Rosin + +description: | + This uses GPIO lines and a challenge & response mechanism to arbitrate who is + the master of an I2C bus in a multimaster situation. + + In many cases using GPIOs to arbitrate is not needed and a design can use the + standard I2C multi-master rules. Using GPIOs is generally useful in the case + where there is a device on the bus that has errata and/or bugs that makes + standard multimaster mode not feasible. + + Note that this scheme works well enough but has some downsides: + * It is nonstandard (not using standard I2C multimaster) + * Having two masters on a bus in general makes it relatively hard to debug + problems (hard to tell if i2c issues were caused by one master, another, + or some device on the bus). + + Algorithm: + All masters on the bus have a 'bus claim' line which is an output that the + others can see. These are all active low with pull-ups enabled. We'll + describe these lines as: + * OUR_CLAIM: output from us signaling to other hosts that we want the bus + * THEIR_CLAIMS: output from others signaling that they want the bus + + The basic algorithm is to assert your line when you want the bus, then make + sure that the other side doesn't want it also. A detailed explanation is + best done with an example. + + Let's say we want to claim the bus. We: + 1. Assert OUR_CLAIM. + 2. Waits a little bit for the other sides to notice (slew time, say 10 + microseconds). + 3. Check THEIR_CLAIMS. If none are asserted then the we have the bus and we + are done. + 4. Otherwise, wait for a few milliseconds and see if THEIR_CLAIMS are released. + 5. If not, back off, release the claim and wait for a few more milliseconds. + 6. Go back to 1 (until retry time has expired). + +properties: + compatible: + const: i2c-arb-gpio-challenge + + i2c-parent: + $ref: /schemas/types.yaml#/definitions/phandle + description: + The I2C bus that this multiplexer's master-side port is connected to. + + our-claim-gpios: + maxItems: 1 + description: + The GPIO that we use to claim the bus. + + slew-delay-us: + default: 10 + description: + Time to wait for a GPIO to go high. + + their-claim-gpios: + minItems: 1 + maxItems: 8 + description: + The GPIOs that the other sides use to claim the bus. Note that some + implementations may only support a single other master. + + wait-free-us: + default: 50000 + description: + We'll give up after this many microseconds. + + wait-retry-us: + default: 3000 + description: + We'll attempt another claim after this many microseconds. + + i2c-arb: + type: object + $ref: /schemas/i2c/i2c-controller.yaml + unevaluatedProperties: false + description: + I2C arbitration bus node. + +required: + - compatible + - i2c-arb + - our-claim-gpios + - their-claim-gpios + +additionalProperties: false + +examples: + - | + #include + #include + + i2c-arbitrator { + compatible = "i2c-arb-gpio-challenge"; + i2c-parent = <&i2c_4>; + + our-claim-gpios = <&gpf0 3 GPIO_ACTIVE_LOW>; + their-claim-gpios = <&gpe0 4 GPIO_ACTIVE_LOW>; + slew-delay-us = <10>; + wait-retry-us = <3000>; + wait-free-us = <50000>; + + i2c-arb { + #address-cells = <1>; + #size-cells = <0>; + + sbs-battery@b { + compatible = "sbs,sbs-battery"; + reg = <0xb>; + sbs,poll-retry-count = <1>; + }; + + embedded-controller@1e { + compatible = "google,cros-ec-i2c"; + reg = <0x1e>; + interrupts = <6 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&gpx1>; + pinctrl-names = "default"; + pinctrl-0 = <&ec_irq>; + wakeup-source; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/i2c/i2c-arb.txt b/Documentation/devicetree/bindings/i2c/i2c-arb.txt deleted file mode 100644 index 59abf9277bdc1..0000000000000 --- a/Documentation/devicetree/bindings/i2c/i2c-arb.txt +++ /dev/null @@ -1,35 +0,0 @@ -Common i2c arbitration bus properties. - -- i2c-arb child node - -Required properties for the i2c-arb child node: -- #address-cells = <1>; -- #size-cells = <0>; - -Optional properties for i2c-arb child node: -- Child nodes conforming to i2c bus binding - - -Example : - - /* - An NXP pca9541 I2C bus master selector at address 0x74 - with a NXP pca8574 GPIO expander attached. - */ - - arb@74 { - compatible = "nxp,pca9541"; - reg = <0x74>; - - i2c-arb { - #address-cells = <1>; - #size-cells = <0>; - - gpio@38 { - compatible = "nxp,pca8574"; - reg = <0x38>; - #gpio-cells = <2>; - gpio-controller; - }; - }; - }; -- GitLab From 55f5cd6148b220c265483e5ace653f8686df3957 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 3 Aug 2023 09:23:31 +0200 Subject: [PATCH 0950/3445] dt-bindings: i2c: cadence: Describe power-domains property ZynqMP Cadence I2c IP core has own power domain that's why describe it as optional property. Signed-off-by: Michal Simek Acked-by: Conor Dooley Link: https://lore.kernel.org/r/8774dba53cae5508f9f7aa173fbaf814d97898b1.1691047405.git.michal.simek@amd.com Signed-off-by: Andi Shyti --- Documentation/devicetree/bindings/i2c/cdns,i2c-r1p10.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/i2c/cdns,i2c-r1p10.yaml b/Documentation/devicetree/bindings/i2c/cdns,i2c-r1p10.yaml index ff57c5416ebcb..9f1d35ce1fe8a 100644 --- a/Documentation/devicetree/bindings/i2c/cdns,i2c-r1p10.yaml +++ b/Documentation/devicetree/bindings/i2c/cdns,i2c-r1p10.yaml @@ -48,6 +48,9 @@ properties: default: 16 enum: [2, 4, 8, 16, 32, 64, 128, 256] + power-domains: + maxItems: 1 + required: - compatible - reg -- GitLab From 5140b46caf337bbad0803a24caa17e4158411d5c Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Mon, 31 Jul 2023 19:27:55 +0800 Subject: [PATCH 0951/3445] i2c: stm32: Do not check for 0 return after calling platform_get_irq() It is not possible for platform_get_irq() to return 0. Use the return value from platform_get_irq(). Signed-off-by: Ruan Jinjie Reviewed-by: Andi Shyti Acked-by: Alain Volmat Link: https://lore.kernel.org/r/20230731112755.1943630-1-ruanjinjie@huawei.com Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-stm32f7.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index e897d9101434d..579b30581725f 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -2121,12 +2121,12 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) phy_addr = (dma_addr_t)res->start; irq_event = platform_get_irq(pdev, 0); - if (irq_event <= 0) - return irq_event ? : -ENOENT; + if (irq_event < 0) + return irq_event; irq_error = platform_get_irq(pdev, 1); - if (irq_error <= 0) - return irq_error ? : -ENOENT; + if (irq_error < 0) + return irq_error; i2c_dev->wakeup_src = of_property_read_bool(pdev->dev.of_node, "wakeup-source"); -- GitLab From 0c89b3257b04950b4d66e9739af3e50bf93c74de Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Tue, 1 Aug 2023 10:53:28 +0800 Subject: [PATCH 0952/3445] i2c: mux: ltc4306: Remove an unnecessary ternary operator The true or false judgement of the ternary operator is unnecessary in C language semantics. So remove it to clean Code. Signed-off-by: Ruan Jinjie Acked-by: Andi Shyti Link: https://lore.kernel.org/r/20230801025328.3380963-1-ruanjinjie@huawei.com Signed-off-by: Andi Shyti --- drivers/i2c/muxes/i2c-mux-ltc4306.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/muxes/i2c-mux-ltc4306.c b/drivers/i2c/muxes/i2c-mux-ltc4306.c index 5a03031519bee..637e25506490d 100644 --- a/drivers/i2c/muxes/i2c-mux-ltc4306.c +++ b/drivers/i2c/muxes/i2c-mux-ltc4306.c @@ -62,7 +62,7 @@ static const struct chip_desc chips[] = { static bool ltc4306_is_volatile_reg(struct device *dev, unsigned int reg) { - return (reg == LTC_REG_CONFIG) ? true : false; + return reg == LTC_REG_CONFIG; } static const struct regmap_config ltc4306_regmap_config = { -- GitLab From 8c49c6e1a7b790c4cb9f464c5485117451d91c60 Mon Sep 17 00:00:00 2001 From: Ivan Babrou Date: Mon, 17 Jul 2023 17:07:37 -0700 Subject: [PATCH 0953/3445] perf script: Print "cgroup" field on the same line as "comm" Commit 3fd7a168bf51 ("perf script: Add 'cgroup' field for output") added support for printing cgroup path in perf script output. It was okay if you didn't want any stacks: $ sudo perf script --comms jpegtran:23f4bf -F comm,tid,cpu,time,cgroup jpegtran:23f4bf 3321915 [013] 404718.587488: /idle.slice/polish.service jpegtran:23f4bf 3321915 [031] 404718.592073: /idle.slice/polish.service With stacks it gets messier as cgroup is printed after the stack: $ perf script --comms jpegtran:23f4bf -F comm,tid,cpu,time,cgroup,ip,sym jpegtran:23f4bf 3321915 [013] 404718.587488: 5c554 compress_output 570d9 jpeg_finish_compress 3476e jpegtran_main 330ee jpegtran::main 326e2 core::ops::function::FnOnce::call_once (inlined) 326e2 std::sys_common::backtrace::__rust_begin_short_backtrace /idle.slice/polish.service jpegtran:23f4bf 3321915 [031] 404718.592073: 8474d jsimd_encode_mcu_AC_first_prepare_sse2.PADDING 55af68e62fff [unknown] /idle.slice/polish.service Let's instead print cgroup on the same line as comm: $ perf script --comms jpegtran:23f4bf -F comm,tid,cpu,time,cgroup,ip,sym jpegtran:23f4bf 3321915 [013] 404718.587488: /idle.slice/polish.service 5c554 compress_output 570d9 jpeg_finish_compress 3476e jpegtran_main 330ee jpegtran::main 326e2 core::ops::function::FnOnce::call_once (inlined) 326e2 std::sys_common::backtrace::__rust_begin_short_backtrace jpegtran:23f4bf 3321915 [031] 404718.592073: /idle.slice/polish.service 8474d jsimd_encode_mcu_AC_first_prepare_sse2.PADDING 55af68e62fff [unknown] Fixes: 3fd7a168bf514979 ("perf script: Add 'cgroup' field for output") Signed-off-by: Ivan Babrou Acked-by: Ian Rogers Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Mark Rutland Cc: Peter Zijlstra Cc: kernel-team@cloudflare.com Link: https://lore.kernel.org/r/20230718000737.49077-1-ivan@cloudflare.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 200b3e7ea8dad..517bf25750c8b 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -2199,6 +2199,17 @@ static void process_event(struct perf_script *script, if (PRINT_FIELD(RETIRE_LAT)) fprintf(fp, "%16" PRIu16, sample->retire_lat); + if (PRINT_FIELD(CGROUP)) { + const char *cgrp_name; + struct cgroup *cgrp = cgroup__find(machine->env, + sample->cgroup); + if (cgrp != NULL) + cgrp_name = cgrp->name; + else + cgrp_name = "unknown"; + fprintf(fp, " %s", cgrp_name); + } + if (PRINT_FIELD(IP)) { struct callchain_cursor *cursor = NULL; @@ -2243,17 +2254,6 @@ static void process_event(struct perf_script *script, if (PRINT_FIELD(CODE_PAGE_SIZE)) fprintf(fp, " %s", get_page_size_name(sample->code_page_size, str)); - if (PRINT_FIELD(CGROUP)) { - const char *cgrp_name; - struct cgroup *cgrp = cgroup__find(machine->env, - sample->cgroup); - if (cgrp != NULL) - cgrp_name = cgrp->name; - else - cgrp_name = "unknown"; - fprintf(fp, " %s", cgrp_name); - } - perf_sample__fprintf_ipc(sample, attr, fp); fprintf(fp, "\n"); -- GitLab From dfaf20af7649c82b0c53103e3bd9f3e6c3751c9d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 25 Jul 2023 16:41:27 +0800 Subject: [PATCH 0954/3445] KVM: arm64: selftests: Replace str_with_index with strdup_printf The original author of aarch64/get-reg-list.c (me) was wearing tunnel vision goggles when implementing str_with_index(). There's no reason to have such a special case string function. Instead, take inspiration from glib and implement strdup_printf. The implementation builds on vasprintf() which requires _GNU_SOURCE, but we require _GNU_SOURCE in most files already. Signed-off-by: Andrew Jones Signed-off-by: Haibo Xu Signed-off-by: Anup Patel --- .../selftests/kvm/aarch64/get-reg-list.c | 23 ++++--------------- .../testing/selftests/kvm/include/test_util.h | 2 ++ tools/testing/selftests/kvm/lib/test_util.c | 15 ++++++++++++ 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index 4f10055af2aa2..52244de20dce2 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -180,19 +180,6 @@ static bool check_supported_feat_reg(struct kvm_vcpu *vcpu, __u64 reg) return true; } -static const char *str_with_index(const char *template, __u64 index) -{ - char *str, *p; - int n; - - str = strdup(template); - p = strstr(str, "##"); - n = sprintf(p, "%lld", index); - strcat(p + n, strstr(template, "##") + 2); - - return (const char *)str; -} - #define REG_MASK (KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_COPROC_MASK) #define CORE_REGS_XX_NR_WORDS 2 @@ -211,7 +198,7 @@ static const char *core_id_to_str(struct vcpu_config *c, __u64 id) KVM_REG_ARM_CORE_REG(regs.regs[30]): idx = (core_off - KVM_REG_ARM_CORE_REG(regs.regs[0])) / CORE_REGS_XX_NR_WORDS; TEST_ASSERT(idx < 31, "%s: Unexpected regs.regs index: %lld", config_name(c), idx); - return str_with_index("KVM_REG_ARM_CORE_REG(regs.regs[##])", idx); + return strdup_printf("KVM_REG_ARM_CORE_REG(regs.regs[%lld])", idx); case KVM_REG_ARM_CORE_REG(regs.sp): return "KVM_REG_ARM_CORE_REG(regs.sp)"; case KVM_REG_ARM_CORE_REG(regs.pc): @@ -226,12 +213,12 @@ static const char *core_id_to_str(struct vcpu_config *c, __u64 id) KVM_REG_ARM_CORE_REG(spsr[KVM_NR_SPSR - 1]): idx = (core_off - KVM_REG_ARM_CORE_REG(spsr[0])) / CORE_SPSR_XX_NR_WORDS; TEST_ASSERT(idx < KVM_NR_SPSR, "%s: Unexpected spsr index: %lld", config_name(c), idx); - return str_with_index("KVM_REG_ARM_CORE_REG(spsr[##])", idx); + return strdup_printf("KVM_REG_ARM_CORE_REG(spsr[%lld])", idx); case KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]) ... KVM_REG_ARM_CORE_REG(fp_regs.vregs[31]): idx = (core_off - KVM_REG_ARM_CORE_REG(fp_regs.vregs[0])) / CORE_FPREGS_XX_NR_WORDS; TEST_ASSERT(idx < 32, "%s: Unexpected fp_regs.vregs index: %lld", config_name(c), idx); - return str_with_index("KVM_REG_ARM_CORE_REG(fp_regs.vregs[##])", idx); + return strdup_printf("KVM_REG_ARM_CORE_REG(fp_regs.vregs[%lld])", idx); case KVM_REG_ARM_CORE_REG(fp_regs.fpsr): return "KVM_REG_ARM_CORE_REG(fp_regs.fpsr)"; case KVM_REG_ARM_CORE_REG(fp_regs.fpcr): @@ -260,13 +247,13 @@ static const char *sve_id_to_str(struct vcpu_config *c, __u64 id) n = (id >> 5) & (KVM_ARM64_SVE_NUM_ZREGS - 1); TEST_ASSERT(id == KVM_REG_ARM64_SVE_ZREG(n, 0), "%s: Unexpected bits set in SVE ZREG id: 0x%llx", config_name(c), id); - return str_with_index("KVM_REG_ARM64_SVE_ZREG(##, 0)", n); + return strdup_printf("KVM_REG_ARM64_SVE_ZREG(%lld, 0)", n); case KVM_REG_ARM64_SVE_PREG_BASE ... KVM_REG_ARM64_SVE_PREG_BASE + (1ULL << 5) * KVM_ARM64_SVE_NUM_PREGS - 1: n = (id >> 5) & (KVM_ARM64_SVE_NUM_PREGS - 1); TEST_ASSERT(id == KVM_REG_ARM64_SVE_PREG(n, 0), "%s: Unexpected bits set in SVE PREG id: 0x%llx", config_name(c), id); - return str_with_index("KVM_REG_ARM64_SVE_PREG(##, 0)", n); + return strdup_printf("KVM_REG_ARM64_SVE_PREG(%lld, 0)", n); case KVM_REG_ARM64_SVE_FFR_BASE: TEST_ASSERT(id == KVM_REG_ARM64_SVE_FFR(0), "%s: Unexpected bits set in SVE FFR id: 0x%llx", config_name(c), id); diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h index a6e9f215ce700..7e0182f837b55 100644 --- a/tools/testing/selftests/kvm/include/test_util.h +++ b/tools/testing/selftests/kvm/include/test_util.h @@ -186,4 +186,6 @@ static inline uint32_t atoi_non_negative(const char *name, const char *num_str) return num; } +char *strdup_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2), nonnull(1))); + #endif /* SELFTEST_KVM_TEST_UTIL_H */ diff --git a/tools/testing/selftests/kvm/lib/test_util.c b/tools/testing/selftests/kvm/lib/test_util.c index b772193f6c186..3e36019eeb4a8 100644 --- a/tools/testing/selftests/kvm/lib/test_util.c +++ b/tools/testing/selftests/kvm/lib/test_util.c @@ -5,6 +5,9 @@ * Copyright (C) 2020, Google LLC. */ +#define _GNU_SOURCE +#include +#include #include #include #include @@ -377,3 +380,15 @@ int atoi_paranoid(const char *num_str) return num; } + +char *strdup_printf(const char *fmt, ...) +{ + va_list ap; + char *str; + + va_start(ap, fmt); + vasprintf(&str, fmt, ap); + va_end(ap); + + return str; +} -- GitLab From 2653860812949d485e18414b72fa542c84763f71 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 25 Jul 2023 16:41:28 +0800 Subject: [PATCH 0955/3445] KVM: arm64: selftests: Drop SVE cap check in print_reg The check doesn't prove much anyway, as the reg lists could be messed up too. Just drop the check to simplify making print_reg more independent. Signed-off-by: Andrew Jones Signed-off-by: Haibo Xu Signed-off-by: Anup Patel --- .../testing/selftests/kvm/aarch64/get-reg-list.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index 52244de20dce2..335bd5eb250ad 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -129,16 +129,6 @@ static const char *config_name(struct vcpu_config *c) return c->name; } -static bool has_cap(struct vcpu_config *c, long capability) -{ - struct reg_sublist *s; - - for_each_sublist(c, s) - if (s->capability == capability) - return true; - return false; -} - static bool filter_reg(__u64 reg) { /* @@ -335,10 +325,7 @@ static void print_reg(struct vcpu_config *c, __u64 id) printf("\tKVM_REG_ARM_FW_FEAT_BMAP_REG(%lld),\n", id & 0xffff); break; case KVM_REG_ARM64_SVE: - if (has_cap(c, KVM_CAP_ARM_SVE)) - printf("\t%s,\n", sve_id_to_str(c, id)); - else - TEST_FAIL("%s: KVM_REG_ARM64_SVE is an unexpected coproc type in reg id: 0x%llx", config_name(c), id); + printf("\t%s,\n", sve_id_to_str(c, id)); break; default: TEST_FAIL("%s: Unexpected coproc type: 0x%llx in reg id: 0x%llx", -- GitLab From c2b5aa7aebbae018edd988e9815087abf72e526b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 25 Jul 2023 16:41:29 +0800 Subject: [PATCH 0956/3445] KVM: arm64: selftests: Remove print_reg's dependency on vcpu_config print_reg() and its helpers only use the vcpu_config pointer for config_name(). So just pass the config name in instead, which is used as a prefix in asserts. print_reg() can now be compiled independently of config_name(). Signed-off-by: Andrew Jones Signed-off-by: Haibo Xu Signed-off-by: Anup Patel --- .../selftests/kvm/aarch64/get-reg-list.c | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index 335bd5eb250ad..c9412be3a04cb 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -176,7 +176,7 @@ static bool check_supported_feat_reg(struct kvm_vcpu *vcpu, __u64 reg) #define CORE_SPSR_XX_NR_WORDS 2 #define CORE_FPREGS_XX_NR_WORDS 4 -static const char *core_id_to_str(struct vcpu_config *c, __u64 id) +static const char *core_id_to_str(const char *prefix, __u64 id) { __u64 core_off = id & ~REG_MASK, idx; @@ -187,7 +187,7 @@ static const char *core_id_to_str(struct vcpu_config *c, __u64 id) case KVM_REG_ARM_CORE_REG(regs.regs[0]) ... KVM_REG_ARM_CORE_REG(regs.regs[30]): idx = (core_off - KVM_REG_ARM_CORE_REG(regs.regs[0])) / CORE_REGS_XX_NR_WORDS; - TEST_ASSERT(idx < 31, "%s: Unexpected regs.regs index: %lld", config_name(c), idx); + TEST_ASSERT(idx < 31, "%s: Unexpected regs.regs index: %lld", prefix, idx); return strdup_printf("KVM_REG_ARM_CORE_REG(regs.regs[%lld])", idx); case KVM_REG_ARM_CORE_REG(regs.sp): return "KVM_REG_ARM_CORE_REG(regs.sp)"; @@ -202,12 +202,12 @@ static const char *core_id_to_str(struct vcpu_config *c, __u64 id) case KVM_REG_ARM_CORE_REG(spsr[0]) ... KVM_REG_ARM_CORE_REG(spsr[KVM_NR_SPSR - 1]): idx = (core_off - KVM_REG_ARM_CORE_REG(spsr[0])) / CORE_SPSR_XX_NR_WORDS; - TEST_ASSERT(idx < KVM_NR_SPSR, "%s: Unexpected spsr index: %lld", config_name(c), idx); + TEST_ASSERT(idx < KVM_NR_SPSR, "%s: Unexpected spsr index: %lld", prefix, idx); return strdup_printf("KVM_REG_ARM_CORE_REG(spsr[%lld])", idx); case KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]) ... KVM_REG_ARM_CORE_REG(fp_regs.vregs[31]): idx = (core_off - KVM_REG_ARM_CORE_REG(fp_regs.vregs[0])) / CORE_FPREGS_XX_NR_WORDS; - TEST_ASSERT(idx < 32, "%s: Unexpected fp_regs.vregs index: %lld", config_name(c), idx); + TEST_ASSERT(idx < 32, "%s: Unexpected fp_regs.vregs index: %lld", prefix, idx); return strdup_printf("KVM_REG_ARM_CORE_REG(fp_regs.vregs[%lld])", idx); case KVM_REG_ARM_CORE_REG(fp_regs.fpsr): return "KVM_REG_ARM_CORE_REG(fp_regs.fpsr)"; @@ -215,11 +215,11 @@ static const char *core_id_to_str(struct vcpu_config *c, __u64 id) return "KVM_REG_ARM_CORE_REG(fp_regs.fpcr)"; } - TEST_FAIL("%s: Unknown core reg id: 0x%llx", config_name(c), id); + TEST_FAIL("%s: Unknown core reg id: 0x%llx", prefix, id); return NULL; } -static const char *sve_id_to_str(struct vcpu_config *c, __u64 id) +static const char *sve_id_to_str(const char *prefix, __u64 id) { __u64 sve_off, n, i; @@ -229,37 +229,37 @@ static const char *sve_id_to_str(struct vcpu_config *c, __u64 id) sve_off = id & ~(REG_MASK | ((1ULL << 5) - 1)); i = id & (KVM_ARM64_SVE_MAX_SLICES - 1); - TEST_ASSERT(i == 0, "%s: Currently we don't expect slice > 0, reg id 0x%llx", config_name(c), id); + TEST_ASSERT(i == 0, "%s: Currently we don't expect slice > 0, reg id 0x%llx", prefix, id); switch (sve_off) { case KVM_REG_ARM64_SVE_ZREG_BASE ... KVM_REG_ARM64_SVE_ZREG_BASE + (1ULL << 5) * KVM_ARM64_SVE_NUM_ZREGS - 1: n = (id >> 5) & (KVM_ARM64_SVE_NUM_ZREGS - 1); TEST_ASSERT(id == KVM_REG_ARM64_SVE_ZREG(n, 0), - "%s: Unexpected bits set in SVE ZREG id: 0x%llx", config_name(c), id); + "%s: Unexpected bits set in SVE ZREG id: 0x%llx", prefix, id); return strdup_printf("KVM_REG_ARM64_SVE_ZREG(%lld, 0)", n); case KVM_REG_ARM64_SVE_PREG_BASE ... KVM_REG_ARM64_SVE_PREG_BASE + (1ULL << 5) * KVM_ARM64_SVE_NUM_PREGS - 1: n = (id >> 5) & (KVM_ARM64_SVE_NUM_PREGS - 1); TEST_ASSERT(id == KVM_REG_ARM64_SVE_PREG(n, 0), - "%s: Unexpected bits set in SVE PREG id: 0x%llx", config_name(c), id); + "%s: Unexpected bits set in SVE PREG id: 0x%llx", prefix, id); return strdup_printf("KVM_REG_ARM64_SVE_PREG(%lld, 0)", n); case KVM_REG_ARM64_SVE_FFR_BASE: TEST_ASSERT(id == KVM_REG_ARM64_SVE_FFR(0), - "%s: Unexpected bits set in SVE FFR id: 0x%llx", config_name(c), id); + "%s: Unexpected bits set in SVE FFR id: 0x%llx", prefix, id); return "KVM_REG_ARM64_SVE_FFR(0)"; } return NULL; } -static void print_reg(struct vcpu_config *c, __u64 id) +static void print_reg(const char *prefix, __u64 id) { unsigned op0, op1, crn, crm, op2; const char *reg_size = NULL; TEST_ASSERT((id & KVM_REG_ARCH_MASK) == KVM_REG_ARM64, - "%s: KVM_REG_ARM64 missing in reg id: 0x%llx", config_name(c), id); + "%s: KVM_REG_ARM64 missing in reg id: 0x%llx", prefix, id); switch (id & KVM_REG_SIZE_MASK) { case KVM_REG_SIZE_U8: @@ -291,16 +291,16 @@ static void print_reg(struct vcpu_config *c, __u64 id) break; default: TEST_FAIL("%s: Unexpected reg size: 0x%llx in reg id: 0x%llx", - config_name(c), (id & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT, id); + prefix, (id & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT, id); } switch (id & KVM_REG_ARM_COPROC_MASK) { case KVM_REG_ARM_CORE: - printf("\tKVM_REG_ARM64 | %s | KVM_REG_ARM_CORE | %s,\n", reg_size, core_id_to_str(c, id)); + printf("\tKVM_REG_ARM64 | %s | KVM_REG_ARM_CORE | %s,\n", reg_size, core_id_to_str(prefix, id)); break; case KVM_REG_ARM_DEMUX: TEST_ASSERT(!(id & ~(REG_MASK | KVM_REG_ARM_DEMUX_ID_MASK | KVM_REG_ARM_DEMUX_VAL_MASK)), - "%s: Unexpected bits set in DEMUX reg id: 0x%llx", config_name(c), id); + "%s: Unexpected bits set in DEMUX reg id: 0x%llx", prefix, id); printf("\tKVM_REG_ARM64 | %s | KVM_REG_ARM_DEMUX | KVM_REG_ARM_DEMUX_ID_CCSIDR | %lld,\n", reg_size, id & KVM_REG_ARM_DEMUX_VAL_MASK); break; @@ -311,25 +311,25 @@ static void print_reg(struct vcpu_config *c, __u64 id) crm = (id & KVM_REG_ARM64_SYSREG_CRM_MASK) >> KVM_REG_ARM64_SYSREG_CRM_SHIFT; op2 = (id & KVM_REG_ARM64_SYSREG_OP2_MASK) >> KVM_REG_ARM64_SYSREG_OP2_SHIFT; TEST_ASSERT(id == ARM64_SYS_REG(op0, op1, crn, crm, op2), - "%s: Unexpected bits set in SYSREG reg id: 0x%llx", config_name(c), id); + "%s: Unexpected bits set in SYSREG reg id: 0x%llx", prefix, id); printf("\tARM64_SYS_REG(%d, %d, %d, %d, %d),\n", op0, op1, crn, crm, op2); break; case KVM_REG_ARM_FW: TEST_ASSERT(id == KVM_REG_ARM_FW_REG(id & 0xffff), - "%s: Unexpected bits set in FW reg id: 0x%llx", config_name(c), id); + "%s: Unexpected bits set in FW reg id: 0x%llx", prefix, id); printf("\tKVM_REG_ARM_FW_REG(%lld),\n", id & 0xffff); break; case KVM_REG_ARM_FW_FEAT_BMAP: TEST_ASSERT(id == KVM_REG_ARM_FW_FEAT_BMAP_REG(id & 0xffff), - "%s: Unexpected bits set in the bitmap feature FW reg id: 0x%llx", config_name(c), id); + "%s: Unexpected bits set in the bitmap feature FW reg id: 0x%llx", prefix, id); printf("\tKVM_REG_ARM_FW_FEAT_BMAP_REG(%lld),\n", id & 0xffff); break; case KVM_REG_ARM64_SVE: - printf("\t%s,\n", sve_id_to_str(c, id)); + printf("\t%s,\n", sve_id_to_str(prefix, id)); break; default: TEST_FAIL("%s: Unexpected coproc type: 0x%llx in reg id: 0x%llx", - config_name(c), (id & KVM_REG_ARM_COPROC_MASK) >> KVM_REG_ARM_COPROC_SHIFT, id); + prefix, (id & KVM_REG_ARM_COPROC_MASK) >> KVM_REG_ARM_COPROC_SHIFT, id); } } @@ -458,7 +458,7 @@ static void run_test(struct vcpu_config *c) __u64 id = reg_list->reg[i]; if ((print_list && !filter_reg(id)) || (print_filtered && filter_reg(id))) - print_reg(c, id); + print_reg(config_name(c), id); } putchar('\n'); return; @@ -486,7 +486,7 @@ static void run_test(struct vcpu_config *c) ret = __vcpu_get_reg(vcpu, reg_list->reg[i], &addr); if (ret) { printf("%s: Failed to get ", config_name(c)); - print_reg(c, reg.id); + print_reg(config_name(c), reg.id); putchar('\n'); ++failed_get; } @@ -498,7 +498,7 @@ static void run_test(struct vcpu_config *c) ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, ®); if (ret != -1 || errno != EPERM) { printf("%s: Failed to reject (ret=%d, errno=%d) ", config_name(c), ret, errno); - print_reg(c, reg.id); + print_reg(config_name(c), reg.id); putchar('\n'); ++failed_reject; } @@ -510,7 +510,7 @@ static void run_test(struct vcpu_config *c) ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, ®); if (ret) { printf("%s: Failed to set ", config_name(c)); - print_reg(c, reg.id); + print_reg(config_name(c), reg.id); putchar('\n'); ++failed_set; } @@ -548,7 +548,7 @@ static void run_test(struct vcpu_config *c) "Consider adding them to the blessed reg " "list with the following lines:\n\n", config_name(c), new_regs); for_each_new_reg(i) - print_reg(c, reg_list->reg[i]); + print_reg(config_name(c), reg_list->reg[i]); putchar('\n'); } @@ -556,7 +556,7 @@ static void run_test(struct vcpu_config *c) printf("\n%s: There are %d missing registers.\n" "The following lines are missing registers:\n\n", config_name(c), missing_regs); for_each_missing_reg(i) - print_reg(c, blessed_reg[i]); + print_reg(config_name(c), blessed_reg[i]); putchar('\n'); } -- GitLab From 9177b715cdccdfd6711511440cf43b8be6e28c6c Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 25 Jul 2023 16:41:30 +0800 Subject: [PATCH 0957/3445] KVM: arm64: selftests: Rename vcpu_config and add to kvm_util.h Rename vcpu_config to vcpu_reg_list to be more specific and add it to kvm_util.h. While it may not get used outside get-reg-list tests, exporting it doesn't hurt, as long as it has a unique enough name. This is a step in the direction of sharing most of the get- reg-list test code between architectures. Signed-off-by: Andrew Jones Signed-off-by: Haibo Xu Signed-off-by: Anup Patel --- .../selftests/kvm/aarch64/get-reg-list.c | 60 +++++++------------ .../selftests/kvm/include/kvm_util_base.h | 16 +++++ 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index c9412be3a04cb..cb6b40e167d06 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -37,17 +37,6 @@ static struct kvm_reg_list *reg_list; static __u64 *blessed_reg, blessed_n; -struct reg_sublist { - const char *name; - long capability; - int feature; - bool finalize; - __u64 *regs; - __u64 regs_n; - __u64 *rejects_set; - __u64 rejects_set_n; -}; - struct feature_id_reg { __u64 reg; __u64 id_reg; @@ -76,12 +65,7 @@ static struct feature_id_reg feat_id_regs[] = { } }; -struct vcpu_config { - char *name; - struct reg_sublist sublists[]; -}; - -static struct vcpu_config *vcpu_configs[]; +static struct vcpu_reg_list *vcpu_configs[]; static int vcpu_configs_n; #define for_each_sublist(c, s) \ @@ -103,9 +87,9 @@ static int vcpu_configs_n; for_each_reg_filtered(i) \ if (!find_reg(blessed_reg, blessed_n, reg_list->reg[i])) -static const char *config_name(struct vcpu_config *c) +static const char *config_name(struct vcpu_reg_list *c) { - struct reg_sublist *s; + struct vcpu_reg_sublist *s; int len = 0; if (c->name) @@ -390,18 +374,18 @@ static void core_reg_fixup(void) reg_list = tmp; } -static void prepare_vcpu_init(struct vcpu_config *c, struct kvm_vcpu_init *init) +static void prepare_vcpu_init(struct vcpu_reg_list *c, struct kvm_vcpu_init *init) { - struct reg_sublist *s; + struct vcpu_reg_sublist *s; for_each_sublist(c, s) if (s->capability) init->features[s->feature / 32] |= 1 << (s->feature % 32); } -static void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_config *c) +static void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c) { - struct reg_sublist *s; + struct vcpu_reg_sublist *s; int feature; for_each_sublist(c, s) { @@ -412,9 +396,9 @@ static void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_config *c) } } -static void check_supported(struct vcpu_config *c) +static void check_supported(struct vcpu_reg_list *c) { - struct reg_sublist *s; + struct vcpu_reg_sublist *s; for_each_sublist(c, s) { if (!s->capability) @@ -430,14 +414,14 @@ static bool print_list; static bool print_filtered; static bool fixup_core_regs; -static void run_test(struct vcpu_config *c) +static void run_test(struct vcpu_reg_list *c) { struct kvm_vcpu_init init = { .target = -1, }; int new_regs = 0, missing_regs = 0, i, n; int failed_get = 0, failed_set = 0, failed_reject = 0; struct kvm_vcpu *vcpu; struct kvm_vm *vm; - struct reg_sublist *s; + struct vcpu_reg_sublist *s; check_supported(c); @@ -574,7 +558,7 @@ static void run_test(struct vcpu_config *c) static void help(void) { - struct vcpu_config *c; + struct vcpu_reg_list *c; int i; printf( @@ -598,9 +582,9 @@ static void help(void) ); } -static struct vcpu_config *parse_config(const char *config) +static struct vcpu_reg_list *parse_config(const char *config) { - struct vcpu_config *c; + struct vcpu_reg_list *c; int i; if (config[8] != '=') @@ -620,7 +604,7 @@ static struct vcpu_config *parse_config(const char *config) int main(int ac, char **av) { - struct vcpu_config *c, *sel = NULL; + struct vcpu_reg_list *c, *sel = NULL; int i, ret = 0; pid_t pid; @@ -1104,14 +1088,14 @@ static __u64 pauth_generic_regs[] = { .regs_n = ARRAY_SIZE(pauth_generic_regs), \ } -static struct vcpu_config vregs_config = { +static struct vcpu_reg_list vregs_config = { .sublists = { BASE_SUBLIST, VREGS_SUBLIST, {0}, }, }; -static struct vcpu_config vregs_pmu_config = { +static struct vcpu_reg_list vregs_pmu_config = { .sublists = { BASE_SUBLIST, VREGS_SUBLIST, @@ -1119,14 +1103,14 @@ static struct vcpu_config vregs_pmu_config = { {0}, }, }; -static struct vcpu_config sve_config = { +static struct vcpu_reg_list sve_config = { .sublists = { BASE_SUBLIST, SVE_SUBLIST, {0}, }, }; -static struct vcpu_config sve_pmu_config = { +static struct vcpu_reg_list sve_pmu_config = { .sublists = { BASE_SUBLIST, SVE_SUBLIST, @@ -1134,7 +1118,7 @@ static struct vcpu_config sve_pmu_config = { {0}, }, }; -static struct vcpu_config pauth_config = { +static struct vcpu_reg_list pauth_config = { .sublists = { BASE_SUBLIST, VREGS_SUBLIST, @@ -1142,7 +1126,7 @@ static struct vcpu_config pauth_config = { {0}, }, }; -static struct vcpu_config pauth_pmu_config = { +static struct vcpu_reg_list pauth_pmu_config = { .sublists = { BASE_SUBLIST, VREGS_SUBLIST, @@ -1152,7 +1136,7 @@ static struct vcpu_config pauth_pmu_config = { }, }; -static struct vcpu_config *vcpu_configs[] = { +static struct vcpu_reg_list *vcpu_configs[] = { &vregs_config, &vregs_pmu_config, &sve_config, diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index eb1ff597bcca9..b5189c7df4828 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -15,6 +15,7 @@ #include #include #include "linux/rbtree.h" +#include #include @@ -124,6 +125,21 @@ struct kvm_vm { uint32_t memslots[NR_MEM_REGIONS]; }; +struct vcpu_reg_sublist { + const char *name; + long capability; + int feature; + bool finalize; + __u64 *regs; + __u64 regs_n; + __u64 *rejects_set; + __u64 rejects_set_n; +}; + +struct vcpu_reg_list { + char *name; + struct vcpu_reg_sublist sublists[]; +}; #define kvm_for_each_vcpu(vm, i, vcpu) \ for ((i) = 0; (i) <= (vm)->last_vcpu_id; (i)++) \ -- GitLab From 0ace6bda5701a38211ac21d45d4683721758e844 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 25 Jul 2023 16:41:31 +0800 Subject: [PATCH 0958/3445] KVM: arm64: selftests: Delete core_reg_fixup core_reg_fixup() complicates sharing the get-reg-list test with other architectures. Rather than work at keeping it, with plenty of #ifdeffery, just delete it, as it's unlikely to test a kernel based on anything older than v5.2 with the get-reg-list test, which is a test meant to check for regressions in new kernels. (And, an older version of the test can still be used for older kernels if necessary.) Signed-off-by: Andrew Jones Signed-off-by: Haibo Xu Signed-off-by: Anup Patel --- .../selftests/kvm/aarch64/get-reg-list.c | 83 +++---------------- 1 file changed, 10 insertions(+), 73 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index cb6b40e167d06..11630bbfb86bf 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -17,12 +17,10 @@ * by running the test with the --list command line argument. * * Note, the blessed list should be created from the oldest possible - * kernel. We can't go older than v4.15, though, because that's the first - * release to expose the ID system registers in KVM_GET_REG_LIST, see - * commit 93390c0a1b20 ("arm64: KVM: Hide unsupported AArch64 CPU features - * from guests"). Also, one must use the --core-reg-fixup command line - * option when running on an older kernel that doesn't include df205b5c6328 - * ("KVM: arm64: Filter out invalid core register IDs in KVM_GET_REG_LIST") + * kernel. We can't go older than v5.2, though, because that's the first + * release which includes df205b5c6328 ("KVM: arm64: Filter out invalid + * core register IDs in KVM_GET_REG_LIST"). Without that commit the core + * registers won't match expectations. */ #include #include @@ -317,63 +315,6 @@ static void print_reg(const char *prefix, __u64 id) } } -/* - * Older kernels listed each 32-bit word of CORE registers separately. - * For 64 and 128-bit registers we need to ignore the extra words. We - * also need to fixup the sizes, because the older kernels stated all - * registers were 64-bit, even when they weren't. - */ -static void core_reg_fixup(void) -{ - struct kvm_reg_list *tmp; - __u64 id, core_off; - int i; - - tmp = calloc(1, sizeof(*tmp) + reg_list->n * sizeof(__u64)); - - for (i = 0; i < reg_list->n; ++i) { - id = reg_list->reg[i]; - - if ((id & KVM_REG_ARM_COPROC_MASK) != KVM_REG_ARM_CORE) { - tmp->reg[tmp->n++] = id; - continue; - } - - core_off = id & ~REG_MASK; - - switch (core_off) { - case 0x52: case 0xd2: case 0xd6: - /* - * These offsets are pointing at padding. - * We need to ignore them too. - */ - continue; - case KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]) ... - KVM_REG_ARM_CORE_REG(fp_regs.vregs[31]): - if (core_off & 3) - continue; - id &= ~KVM_REG_SIZE_MASK; - id |= KVM_REG_SIZE_U128; - tmp->reg[tmp->n++] = id; - continue; - case KVM_REG_ARM_CORE_REG(fp_regs.fpsr): - case KVM_REG_ARM_CORE_REG(fp_regs.fpcr): - id &= ~KVM_REG_SIZE_MASK; - id |= KVM_REG_SIZE_U32; - tmp->reg[tmp->n++] = id; - continue; - default: - if (core_off & 1) - continue; - tmp->reg[tmp->n++] = id; - break; - } - } - - free(reg_list); - reg_list = tmp; -} - static void prepare_vcpu_init(struct vcpu_reg_list *c, struct kvm_vcpu_init *init) { struct vcpu_reg_sublist *s; @@ -412,7 +353,6 @@ static void check_supported(struct vcpu_reg_list *c) static bool print_list; static bool print_filtered; -static bool fixup_core_regs; static void run_test(struct vcpu_reg_list *c) { @@ -433,9 +373,6 @@ static void run_test(struct vcpu_reg_list *c) reg_list = vcpu_get_reg_list(vcpu); - if (fixup_core_regs) - core_reg_fixup(); - if (print_list || print_filtered) { putchar('\n'); for_each_reg(i) { @@ -563,7 +500,7 @@ static void help(void) printf( "\n" - "usage: get-reg-list [--config=] [--list] [--list-filtered] [--core-reg-fixup]\n\n" + "usage: get-reg-list [--config=] [--list] [--list-filtered]\n\n" " --config= Used to select a specific vcpu configuration for the test/listing\n" " '' may be\n"); @@ -577,7 +514,6 @@ static void help(void) "\n" " --list Print the register list rather than test it (requires --config)\n" " --list-filtered Print registers that would normally be filtered out (requires --config)\n" - " --core-reg-fixup Needed when running on old kernels with broken core reg listings\n" "\n" ); } @@ -609,9 +545,7 @@ int main(int ac, char **av) pid_t pid; for (i = 1; i < ac; ++i) { - if (strcmp(av[i], "--core-reg-fixup") == 0) - fixup_core_regs = true; - else if (strncmp(av[i], "--config", 8) == 0) + if (strncmp(av[i], "--config", 8) == 0) sel = parse_config(av[i]); else if (strcmp(av[i], "--list") == 0) print_list = true; @@ -654,8 +588,11 @@ int main(int ac, char **av) } /* - * The current blessed list was primed with the output of kernel version + * The original blessed list was primed with the output of kernel version * v4.15 with --core-reg-fixup and then later updated with new registers. + * (The --core-reg-fixup option and it's fixup function have been removed + * from the test, as it's unlikely to use this type of test on a kernel + * older than v5.2.) * * The blessed list is up to date with kernel version v6.4 (or so we hope) */ -- GitLab From d952f54d01ec2ea5ee9d5e21f2ea3a5807b4bcbc Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Fri, 4 Aug 2023 21:04:18 +0800 Subject: [PATCH 0959/3445] RDMA/hns: Remove unused declaration hns_roce_modify_srq() Commit c7bcb13442e1 ("RDMA/hns: Add SRQ support for hip08 kernel mode") declared but never implemented this. Signed-off-by: Yue Haibing Link: https://lore.kernel.org/r/20230804130418.41728-1-yuehaibing@huawei.com Reviewed-by: Junxian Huang Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/hns/hns_roce_device.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index bfe4d84897add..9691cfdd7e3d7 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -1160,9 +1160,6 @@ int hns_roce_get_umem_bufs(struct hns_roce_dev *hr_dev, dma_addr_t *bufs, int hns_roce_create_srq(struct ib_srq *srq, struct ib_srq_init_attr *srq_init_attr, struct ib_udata *udata); -int hns_roce_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr, - enum ib_srq_attr_mask srq_attr_mask, - struct ib_udata *udata); int hns_roce_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata); int hns_roce_alloc_xrcd(struct ib_xrcd *ib_xrcd, struct ib_udata *udata); -- GitLab From 4460a7dc77d00340c59f7e4252c65efd5fbe877b Mon Sep 17 00:00:00 2001 From: Fuad Tabba Date: Mon, 31 Jul 2023 12:40:31 +0100 Subject: [PATCH 0960/3445] KVM: arm64: Remove redundant kvm_set_pfn_accessed() from user_mem_abort() The function user_mem_abort() calls kvm_release_pfn_clean(), which eventually calls kvm_set_page_accessed(). Therefore, remove the redundant call to kvm_set_pfn_accessed(). Signed-off-by: Fuad Tabba Reviewed-by: Shaoqin Huang Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20230731114110.2673451-1-tabba@google.com --- arch/arm64/kvm/mmu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index d3b4feed460c0..137b775d238b9 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1541,7 +1541,6 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, out_unlock: read_unlock(&kvm->mmu_lock); - kvm_set_pfn_accessed(pfn); kvm_release_pfn_clean(pfn); return ret != -EAGAIN ? ret : 0; } -- GitLab From 17da79e009c376523ab977a351a2a69bad8e847b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 25 Jul 2023 16:41:32 +0800 Subject: [PATCH 0961/3445] KVM: arm64: selftests: Split get-reg-list test code Split the arch-neutral test code out of aarch64/get-reg-list.c into get-reg-list.c. To do this we invent a new make variable $(SPLIT_TESTS) which expects common parts to be in the KVM selftests root and the counterparts to have the same name, but be in $(ARCH_DIR). There's still some work to be done to de-aarch64 the common get-reg-list.c, but we leave that to the next patch to avoid modifying too much code while moving it. Signed-off-by: Andrew Jones Signed-off-by: Haibo Xu Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/Makefile | 12 +- .../selftests/kvm/aarch64/get-reg-list.c | 367 +---------------- tools/testing/selftests/kvm/get-reg-list.c | 377 ++++++++++++++++++ 3 files changed, 398 insertions(+), 358 deletions(-) create mode 100644 tools/testing/selftests/kvm/get-reg-list.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index c692cc86e7da8..95f180e711d5a 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -140,7 +140,6 @@ TEST_GEN_PROGS_EXTENDED_x86_64 += x86_64/nx_huge_pages_test TEST_GEN_PROGS_aarch64 += aarch64/aarch32_id_regs TEST_GEN_PROGS_aarch64 += aarch64/arch_timer TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions -TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list TEST_GEN_PROGS_aarch64 += aarch64/hypercalls TEST_GEN_PROGS_aarch64 += aarch64/page_fault_test TEST_GEN_PROGS_aarch64 += aarch64/psci_test @@ -152,6 +151,7 @@ TEST_GEN_PROGS_aarch64 += access_tracking_perf_test TEST_GEN_PROGS_aarch64 += demand_paging_test TEST_GEN_PROGS_aarch64 += dirty_log_test TEST_GEN_PROGS_aarch64 += dirty_log_perf_test +TEST_GEN_PROGS_aarch64 += get-reg-list TEST_GEN_PROGS_aarch64 += kvm_create_max_vcpus TEST_GEN_PROGS_aarch64 += kvm_page_table_test TEST_GEN_PROGS_aarch64 += memslot_modification_stress_test @@ -181,6 +181,8 @@ TEST_GEN_PROGS_riscv += kvm_page_table_test TEST_GEN_PROGS_riscv += set_memory_region_test TEST_GEN_PROGS_riscv += kvm_binary_stats_test +SPLIT_TESTS += get-reg-list + TEST_PROGS += $(TEST_PROGS_$(ARCH_DIR)) TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(ARCH_DIR)) TEST_GEN_PROGS_EXTENDED += $(TEST_GEN_PROGS_EXTENDED_$(ARCH_DIR)) @@ -228,11 +230,14 @@ LIBKVM_C_OBJ := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBKVM_C)) LIBKVM_S_OBJ := $(patsubst %.S, $(OUTPUT)/%.o, $(LIBKVM_S)) LIBKVM_STRING_OBJ := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBKVM_STRING)) LIBKVM_OBJS = $(LIBKVM_C_OBJ) $(LIBKVM_S_OBJ) $(LIBKVM_STRING_OBJ) +SPLIT_TESTS_TARGETS := $(patsubst %, $(OUTPUT)/%, $(SPLIT_TESTS)) +SPLIT_TESTS_OBJS := $(patsubst %, $(ARCH_DIR)/%.o, $(SPLIT_TESTS)) TEST_GEN_OBJ = $(patsubst %, %.o, $(TEST_GEN_PROGS)) TEST_GEN_OBJ += $(patsubst %, %.o, $(TEST_GEN_PROGS_EXTENDED)) TEST_DEP_FILES = $(patsubst %.o, %.d, $(TEST_GEN_OBJ)) TEST_DEP_FILES += $(patsubst %.o, %.d, $(LIBKVM_OBJS)) +TEST_DEP_FILES += $(patsubst %.o, %.d, $(SPLIT_TESTS_OBJS)) -include $(TEST_DEP_FILES) $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): %: %.o @@ -240,7 +245,10 @@ $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): %: %.o $(TEST_GEN_OBJ): $(OUTPUT)/%.o: %.c $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ -EXTRA_CLEAN += $(LIBKVM_OBJS) $(TEST_DEP_FILES) $(TEST_GEN_OBJ) cscope.* +$(SPLIT_TESTS_TARGETS): %: %.o $(SPLIT_TESTS_OBJS) + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $^ $(LDLIBS) -o $@ + +EXTRA_CLEAN += $(LIBKVM_OBJS) $(TEST_DEP_FILES) $(TEST_GEN_OBJ) $(SPLIT_TESTS_OBJS) cscope.* x := $(shell mkdir -p $(sort $(dir $(LIBKVM_C_OBJ) $(LIBKVM_S_OBJ)))) $(LIBKVM_C_OBJ): $(OUTPUT)/%.o: %.c diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index 11630bbfb86bf..f72f1a522ff4c 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -4,37 +4,17 @@ * * Copyright (C) 2020, Red Hat, Inc. * - * When attempting to migrate from a host with an older kernel to a host - * with a newer kernel we allow the newer kernel on the destination to - * list new registers with get-reg-list. We assume they'll be unused, at - * least until the guest reboots, and so they're relatively harmless. - * However, if the destination host with the newer kernel is missing - * registers which the source host with the older kernel has, then that's - * a regression in get-reg-list. This test checks for that regression by - * checking the current list against a blessed list. We should never have - * missing registers, but if new ones appear then they can probably be - * added to the blessed list. A completely new blessed list can be created - * by running the test with the --list command line argument. - * - * Note, the blessed list should be created from the oldest possible - * kernel. We can't go older than v5.2, though, because that's the first + * While the blessed list should be created from the oldest possible + * kernel, we can't go older than v5.2, though, because that's the first * release which includes df205b5c6328 ("KVM: arm64: Filter out invalid * core register IDs in KVM_GET_REG_LIST"). Without that commit the core * registers won't match expectations. */ #include -#include -#include -#include -#include -#include #include "kvm_util.h" #include "test_util.h" #include "processor.h" -static struct kvm_reg_list *reg_list; -static __u64 *blessed_reg, blessed_n; - struct feature_id_reg { __u64 reg; __u64 id_reg; @@ -63,55 +43,7 @@ static struct feature_id_reg feat_id_regs[] = { } }; -static struct vcpu_reg_list *vcpu_configs[]; -static int vcpu_configs_n; - -#define for_each_sublist(c, s) \ - for ((s) = &(c)->sublists[0]; (s)->regs; ++(s)) - -#define for_each_reg(i) \ - for ((i) = 0; (i) < reg_list->n; ++(i)) - -#define for_each_reg_filtered(i) \ - for_each_reg(i) \ - if (!filter_reg(reg_list->reg[i])) - -#define for_each_missing_reg(i) \ - for ((i) = 0; (i) < blessed_n; ++(i)) \ - if (!find_reg(reg_list->reg, reg_list->n, blessed_reg[i])) \ - if (check_supported_feat_reg(vcpu, blessed_reg[i])) - -#define for_each_new_reg(i) \ - for_each_reg_filtered(i) \ - if (!find_reg(blessed_reg, blessed_n, reg_list->reg[i])) - -static const char *config_name(struct vcpu_reg_list *c) -{ - struct vcpu_reg_sublist *s; - int len = 0; - - if (c->name) - return c->name; - - for_each_sublist(c, s) - len += strlen(s->name) + 1; - - c->name = malloc(len); - - len = 0; - for_each_sublist(c, s) { - if (!strcmp(s->name, "base")) - continue; - strcat(c->name + len, s->name); - len += strlen(s->name) + 1; - c->name[len - 1] = '+'; - } - c->name[len - 1] = '\0'; - - return c->name; -} - -static bool filter_reg(__u64 reg) +bool filter_reg(__u64 reg) { /* * DEMUX register presence depends on the host's CLIDR_EL1. @@ -123,16 +55,6 @@ static bool filter_reg(__u64 reg) return false; } -static bool find_reg(__u64 regs[], __u64 nr_regs, __u64 reg) -{ - int i; - - for (i = 0; i < nr_regs; ++i) - if (reg == regs[i]) - return true; - return false; -} - static bool check_supported_feat_reg(struct kvm_vcpu *vcpu, __u64 reg) { int i, ret; @@ -152,6 +74,11 @@ static bool check_supported_feat_reg(struct kvm_vcpu *vcpu, __u64 reg) return true; } +bool check_supported_reg(struct kvm_vcpu *vcpu, __u64 reg) +{ + return check_supported_feat_reg(vcpu, reg); +} + #define REG_MASK (KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_COPROC_MASK) #define CORE_REGS_XX_NR_WORDS 2 @@ -235,7 +162,7 @@ static const char *sve_id_to_str(const char *prefix, __u64 id) return NULL; } -static void print_reg(const char *prefix, __u64 id) +void print_reg(const char *prefix, __u64 id) { unsigned op0, op1, crn, crm, op2; const char *reg_size = NULL; @@ -315,278 +242,6 @@ static void print_reg(const char *prefix, __u64 id) } } -static void prepare_vcpu_init(struct vcpu_reg_list *c, struct kvm_vcpu_init *init) -{ - struct vcpu_reg_sublist *s; - - for_each_sublist(c, s) - if (s->capability) - init->features[s->feature / 32] |= 1 << (s->feature % 32); -} - -static void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c) -{ - struct vcpu_reg_sublist *s; - int feature; - - for_each_sublist(c, s) { - if (s->finalize) { - feature = s->feature; - vcpu_ioctl(vcpu, KVM_ARM_VCPU_FINALIZE, &feature); - } - } -} - -static void check_supported(struct vcpu_reg_list *c) -{ - struct vcpu_reg_sublist *s; - - for_each_sublist(c, s) { - if (!s->capability) - continue; - - __TEST_REQUIRE(kvm_has_cap(s->capability), - "%s: %s not available, skipping tests\n", - config_name(c), s->name); - } -} - -static bool print_list; -static bool print_filtered; - -static void run_test(struct vcpu_reg_list *c) -{ - struct kvm_vcpu_init init = { .target = -1, }; - int new_regs = 0, missing_regs = 0, i, n; - int failed_get = 0, failed_set = 0, failed_reject = 0; - struct kvm_vcpu *vcpu; - struct kvm_vm *vm; - struct vcpu_reg_sublist *s; - - check_supported(c); - - vm = vm_create_barebones(); - prepare_vcpu_init(c, &init); - vcpu = __vm_vcpu_add(vm, 0); - aarch64_vcpu_setup(vcpu, &init); - finalize_vcpu(vcpu, c); - - reg_list = vcpu_get_reg_list(vcpu); - - if (print_list || print_filtered) { - putchar('\n'); - for_each_reg(i) { - __u64 id = reg_list->reg[i]; - if ((print_list && !filter_reg(id)) || - (print_filtered && filter_reg(id))) - print_reg(config_name(c), id); - } - putchar('\n'); - return; - } - - /* - * We only test that we can get the register and then write back the - * same value. Some registers may allow other values to be written - * back, but others only allow some bits to be changed, and at least - * for ID registers set will fail if the value does not exactly match - * what was returned by get. If registers that allow other values to - * be written need to have the other values tested, then we should - * create a new set of tests for those in a new independent test - * executable. - */ - for_each_reg(i) { - uint8_t addr[2048 / 8]; - struct kvm_one_reg reg = { - .id = reg_list->reg[i], - .addr = (__u64)&addr, - }; - bool reject_reg = false; - int ret; - - ret = __vcpu_get_reg(vcpu, reg_list->reg[i], &addr); - if (ret) { - printf("%s: Failed to get ", config_name(c)); - print_reg(config_name(c), reg.id); - putchar('\n'); - ++failed_get; - } - - /* rejects_set registers are rejected after KVM_ARM_VCPU_FINALIZE */ - for_each_sublist(c, s) { - if (s->rejects_set && find_reg(s->rejects_set, s->rejects_set_n, reg.id)) { - reject_reg = true; - ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, ®); - if (ret != -1 || errno != EPERM) { - printf("%s: Failed to reject (ret=%d, errno=%d) ", config_name(c), ret, errno); - print_reg(config_name(c), reg.id); - putchar('\n'); - ++failed_reject; - } - break; - } - } - - if (!reject_reg) { - ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, ®); - if (ret) { - printf("%s: Failed to set ", config_name(c)); - print_reg(config_name(c), reg.id); - putchar('\n'); - ++failed_set; - } - } - } - - for_each_sublist(c, s) - blessed_n += s->regs_n; - blessed_reg = calloc(blessed_n, sizeof(__u64)); - - n = 0; - for_each_sublist(c, s) { - for (i = 0; i < s->regs_n; ++i) - blessed_reg[n++] = s->regs[i]; - } - - for_each_new_reg(i) - ++new_regs; - - for_each_missing_reg(i) - ++missing_regs; - - if (new_regs || missing_regs) { - n = 0; - for_each_reg_filtered(i) - ++n; - - printf("%s: Number blessed registers: %5lld\n", config_name(c), blessed_n); - printf("%s: Number registers: %5lld (includes %lld filtered registers)\n", - config_name(c), reg_list->n, reg_list->n - n); - } - - if (new_regs) { - printf("\n%s: There are %d new registers.\n" - "Consider adding them to the blessed reg " - "list with the following lines:\n\n", config_name(c), new_regs); - for_each_new_reg(i) - print_reg(config_name(c), reg_list->reg[i]); - putchar('\n'); - } - - if (missing_regs) { - printf("\n%s: There are %d missing registers.\n" - "The following lines are missing registers:\n\n", config_name(c), missing_regs); - for_each_missing_reg(i) - print_reg(config_name(c), blessed_reg[i]); - putchar('\n'); - } - - TEST_ASSERT(!missing_regs && !failed_get && !failed_set && !failed_reject, - "%s: There are %d missing registers; " - "%d registers failed get; %d registers failed set; %d registers failed reject", - config_name(c), missing_regs, failed_get, failed_set, failed_reject); - - pr_info("%s: PASS\n", config_name(c)); - blessed_n = 0; - free(blessed_reg); - free(reg_list); - kvm_vm_free(vm); -} - -static void help(void) -{ - struct vcpu_reg_list *c; - int i; - - printf( - "\n" - "usage: get-reg-list [--config=] [--list] [--list-filtered]\n\n" - " --config= Used to select a specific vcpu configuration for the test/listing\n" - " '' may be\n"); - - for (i = 0; i < vcpu_configs_n; ++i) { - c = vcpu_configs[i]; - printf( - " '%s'\n", config_name(c)); - } - - printf( - "\n" - " --list Print the register list rather than test it (requires --config)\n" - " --list-filtered Print registers that would normally be filtered out (requires --config)\n" - "\n" - ); -} - -static struct vcpu_reg_list *parse_config(const char *config) -{ - struct vcpu_reg_list *c; - int i; - - if (config[8] != '=') - help(), exit(1); - - for (i = 0; i < vcpu_configs_n; ++i) { - c = vcpu_configs[i]; - if (strcmp(config_name(c), &config[9]) == 0) - break; - } - - if (i == vcpu_configs_n) - help(), exit(1); - - return c; -} - -int main(int ac, char **av) -{ - struct vcpu_reg_list *c, *sel = NULL; - int i, ret = 0; - pid_t pid; - - for (i = 1; i < ac; ++i) { - if (strncmp(av[i], "--config", 8) == 0) - sel = parse_config(av[i]); - else if (strcmp(av[i], "--list") == 0) - print_list = true; - else if (strcmp(av[i], "--list-filtered") == 0) - print_filtered = true; - else if (strcmp(av[i], "--help") == 0 || strcmp(av[1], "-h") == 0) - help(), exit(0); - else - help(), exit(1); - } - - if (print_list || print_filtered) { - /* - * We only want to print the register list of a single config. - */ - if (!sel) - help(), exit(1); - } - - for (i = 0; i < vcpu_configs_n; ++i) { - c = vcpu_configs[i]; - if (sel && c != sel) - continue; - - pid = fork(); - - if (!pid) { - run_test(c); - exit(0); - } else { - int wstatus; - pid_t wpid = wait(&wstatus); - TEST_ASSERT(wpid == pid && WIFEXITED(wstatus), "wait: Unexpected return"); - if (WEXITSTATUS(wstatus) && WEXITSTATUS(wstatus) != KSFT_SKIP) - ret = KSFT_FAIL; - } - } - - return ret; -} - /* * The original blessed list was primed with the output of kernel version * v4.15 with --core-reg-fixup and then later updated with new registers. @@ -1073,7 +728,7 @@ static struct vcpu_reg_list pauth_pmu_config = { }, }; -static struct vcpu_reg_list *vcpu_configs[] = { +struct vcpu_reg_list *vcpu_configs[] = { &vregs_config, &vregs_pmu_config, &sve_config, @@ -1081,4 +736,4 @@ static struct vcpu_reg_list *vcpu_configs[] = { &pauth_config, &pauth_pmu_config, }; -static int vcpu_configs_n = ARRAY_SIZE(vcpu_configs); +int vcpu_configs_n = ARRAY_SIZE(vcpu_configs); diff --git a/tools/testing/selftests/kvm/get-reg-list.c b/tools/testing/selftests/kvm/get-reg-list.c new file mode 100644 index 0000000000000..a29e548643d11 --- /dev/null +++ b/tools/testing/selftests/kvm/get-reg-list.c @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Check for KVM_GET_REG_LIST regressions. + * + * Copyright (C) 2020, Red Hat, Inc. + * + * When attempting to migrate from a host with an older kernel to a host + * with a newer kernel we allow the newer kernel on the destination to + * list new registers with get-reg-list. We assume they'll be unused, at + * least until the guest reboots, and so they're relatively harmless. + * However, if the destination host with the newer kernel is missing + * registers which the source host with the older kernel has, then that's + * a regression in get-reg-list. This test checks for that regression by + * checking the current list against a blessed list. We should never have + * missing registers, but if new ones appear then they can probably be + * added to the blessed list. A completely new blessed list can be created + * by running the test with the --list command line argument. + * + * The blessed list should be created from the oldest possible kernel. + */ +#include +#include +#include +#include +#include +#include +#include "kvm_util.h" +#include "test_util.h" +#include "processor.h" + +static struct kvm_reg_list *reg_list; +static __u64 *blessed_reg, blessed_n; + +extern struct vcpu_reg_list *vcpu_configs[]; +extern int vcpu_configs_n; + +#define for_each_sublist(c, s) \ + for ((s) = &(c)->sublists[0]; (s)->regs; ++(s)) + +#define for_each_reg(i) \ + for ((i) = 0; (i) < reg_list->n; ++(i)) + +#define for_each_reg_filtered(i) \ + for_each_reg(i) \ + if (!filter_reg(reg_list->reg[i])) + +#define for_each_missing_reg(i) \ + for ((i) = 0; (i) < blessed_n; ++(i)) \ + if (!find_reg(reg_list->reg, reg_list->n, blessed_reg[i])) \ + if (check_supported_reg(vcpu, blessed_reg[i])) + +#define for_each_new_reg(i) \ + for_each_reg_filtered(i) \ + if (!find_reg(blessed_reg, blessed_n, reg_list->reg[i])) + +static const char *config_name(struct vcpu_reg_list *c) +{ + struct vcpu_reg_sublist *s; + int len = 0; + + if (c->name) + return c->name; + + for_each_sublist(c, s) + len += strlen(s->name) + 1; + + c->name = malloc(len); + + len = 0; + for_each_sublist(c, s) { + if (!strcmp(s->name, "base")) + continue; + strcat(c->name + len, s->name); + len += strlen(s->name) + 1; + c->name[len - 1] = '+'; + } + c->name[len - 1] = '\0'; + + return c->name; +} + +bool __weak check_supported_reg(struct kvm_vcpu *vcpu, __u64 reg) +{ + return true; +} + +bool __weak filter_reg(__u64 reg) +{ + return false; +} + +static bool find_reg(__u64 regs[], __u64 nr_regs, __u64 reg) +{ + int i; + + for (i = 0; i < nr_regs; ++i) + if (reg == regs[i]) + return true; + return false; +} + +void __weak print_reg(const char *prefix, __u64 id) +{ + printf("\t0x%llx,\n", id); +} + +static void prepare_vcpu_init(struct vcpu_reg_list *c, struct kvm_vcpu_init *init) +{ + struct vcpu_reg_sublist *s; + + for_each_sublist(c, s) + if (s->capability) + init->features[s->feature / 32] |= 1 << (s->feature % 32); +} + +static void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c) +{ + struct vcpu_reg_sublist *s; + int feature; + + for_each_sublist(c, s) { + if (s->finalize) { + feature = s->feature; + vcpu_ioctl(vcpu, KVM_ARM_VCPU_FINALIZE, &feature); + } + } +} + +static void check_supported(struct vcpu_reg_list *c) +{ + struct vcpu_reg_sublist *s; + + for_each_sublist(c, s) { + if (!s->capability) + continue; + + __TEST_REQUIRE(kvm_has_cap(s->capability), + "%s: %s not available, skipping tests\n", + config_name(c), s->name); + } +} + +static bool print_list; +static bool print_filtered; + +static void run_test(struct vcpu_reg_list *c) +{ + struct kvm_vcpu_init init = { .target = -1, }; + int new_regs = 0, missing_regs = 0, i, n; + int failed_get = 0, failed_set = 0, failed_reject = 0; + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + struct vcpu_reg_sublist *s; + + check_supported(c); + + vm = vm_create_barebones(); + prepare_vcpu_init(c, &init); + vcpu = __vm_vcpu_add(vm, 0); + aarch64_vcpu_setup(vcpu, &init); + finalize_vcpu(vcpu, c); + + reg_list = vcpu_get_reg_list(vcpu); + + if (print_list || print_filtered) { + putchar('\n'); + for_each_reg(i) { + __u64 id = reg_list->reg[i]; + if ((print_list && !filter_reg(id)) || + (print_filtered && filter_reg(id))) + print_reg(config_name(c), id); + } + putchar('\n'); + return; + } + + /* + * We only test that we can get the register and then write back the + * same value. Some registers may allow other values to be written + * back, but others only allow some bits to be changed, and at least + * for ID registers set will fail if the value does not exactly match + * what was returned by get. If registers that allow other values to + * be written need to have the other values tested, then we should + * create a new set of tests for those in a new independent test + * executable. + */ + for_each_reg(i) { + uint8_t addr[2048 / 8]; + struct kvm_one_reg reg = { + .id = reg_list->reg[i], + .addr = (__u64)&addr, + }; + bool reject_reg = false; + int ret; + + ret = __vcpu_get_reg(vcpu, reg_list->reg[i], &addr); + if (ret) { + printf("%s: Failed to get ", config_name(c)); + print_reg(config_name(c), reg.id); + putchar('\n'); + ++failed_get; + } + + /* rejects_set registers are rejected after KVM_ARM_VCPU_FINALIZE */ + for_each_sublist(c, s) { + if (s->rejects_set && find_reg(s->rejects_set, s->rejects_set_n, reg.id)) { + reject_reg = true; + ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, ®); + if (ret != -1 || errno != EPERM) { + printf("%s: Failed to reject (ret=%d, errno=%d) ", config_name(c), ret, errno); + print_reg(config_name(c), reg.id); + putchar('\n'); + ++failed_reject; + } + break; + } + } + + if (!reject_reg) { + ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, ®); + if (ret) { + printf("%s: Failed to set ", config_name(c)); + print_reg(config_name(c), reg.id); + putchar('\n'); + ++failed_set; + } + } + } + + for_each_sublist(c, s) + blessed_n += s->regs_n; + blessed_reg = calloc(blessed_n, sizeof(__u64)); + + n = 0; + for_each_sublist(c, s) { + for (i = 0; i < s->regs_n; ++i) + blessed_reg[n++] = s->regs[i]; + } + + for_each_new_reg(i) + ++new_regs; + + for_each_missing_reg(i) + ++missing_regs; + + if (new_regs || missing_regs) { + n = 0; + for_each_reg_filtered(i) + ++n; + + printf("%s: Number blessed registers: %5lld\n", config_name(c), blessed_n); + printf("%s: Number registers: %5lld (includes %lld filtered registers)\n", + config_name(c), reg_list->n, reg_list->n - n); + } + + if (new_regs) { + printf("\n%s: There are %d new registers.\n" + "Consider adding them to the blessed reg " + "list with the following lines:\n\n", config_name(c), new_regs); + for_each_new_reg(i) + print_reg(config_name(c), reg_list->reg[i]); + putchar('\n'); + } + + if (missing_regs) { + printf("\n%s: There are %d missing registers.\n" + "The following lines are missing registers:\n\n", config_name(c), missing_regs); + for_each_missing_reg(i) + print_reg(config_name(c), blessed_reg[i]); + putchar('\n'); + } + + TEST_ASSERT(!missing_regs && !failed_get && !failed_set && !failed_reject, + "%s: There are %d missing registers; " + "%d registers failed get; %d registers failed set; %d registers failed reject", + config_name(c), missing_regs, failed_get, failed_set, failed_reject); + + pr_info("%s: PASS\n", config_name(c)); + blessed_n = 0; + free(blessed_reg); + free(reg_list); + kvm_vm_free(vm); +} + +static void help(void) +{ + struct vcpu_reg_list *c; + int i; + + printf( + "\n" + "usage: get-reg-list [--config=] [--list] [--list-filtered]\n\n" + " --config= Used to select a specific vcpu configuration for the test/listing\n" + " '' may be\n"); + + for (i = 0; i < vcpu_configs_n; ++i) { + c = vcpu_configs[i]; + printf( + " '%s'\n", config_name(c)); + } + + printf( + "\n" + " --list Print the register list rather than test it (requires --config)\n" + " --list-filtered Print registers that would normally be filtered out (requires --config)\n" + "\n" + ); +} + +static struct vcpu_reg_list *parse_config(const char *config) +{ + struct vcpu_reg_list *c = NULL; + int i; + + if (config[8] != '=') + help(), exit(1); + + for (i = 0; i < vcpu_configs_n; ++i) { + c = vcpu_configs[i]; + if (strcmp(config_name(c), &config[9]) == 0) + break; + } + + if (i == vcpu_configs_n) + help(), exit(1); + + return c; +} + +int main(int ac, char **av) +{ + struct vcpu_reg_list *c, *sel = NULL; + int i, ret = 0; + pid_t pid; + + for (i = 1; i < ac; ++i) { + if (strncmp(av[i], "--config", 8) == 0) + sel = parse_config(av[i]); + else if (strcmp(av[i], "--list") == 0) + print_list = true; + else if (strcmp(av[i], "--list-filtered") == 0) + print_filtered = true; + else if (strcmp(av[i], "--help") == 0 || strcmp(av[1], "-h") == 0) + help(), exit(0); + else + help(), exit(1); + } + + if (print_list || print_filtered) { + /* + * We only want to print the register list of a single config. + */ + if (!sel) + help(), exit(1); + } + + for (i = 0; i < vcpu_configs_n; ++i) { + c = vcpu_configs[i]; + if (sel && c != sel) + continue; + + pid = fork(); + + if (!pid) { + run_test(c); + exit(0); + } else { + int wstatus; + pid_t wpid = wait(&wstatus); + TEST_ASSERT(wpid == pid && WIFEXITED(wstatus), "wait: Unexpected return"); + if (WEXITSTATUS(wstatus) && WEXITSTATUS(wstatus) != KSFT_SKIP) + ret = KSFT_FAIL; + } + } + + return ret; +} -- GitLab From be4c58060c3efd1f8dff59e59ff8e69d08f00560 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 25 Jul 2023 16:41:33 +0800 Subject: [PATCH 0962/3445] KVM: arm64: selftests: Finish generalizing get-reg-list Add some unfortunate #ifdeffery to ensure the common get-reg-list.c can be compiled and run with other architectures. The next architecture to support get-reg-list should now only need to provide $(ARCH_DIR)/get-reg-list.c where arch-specific print_reg() and vcpu_configs[] get defined. Signed-off-by: Andrew Jones Signed-off-by: Haibo Xu Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/get-reg-list.c | 26 +++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/kvm/get-reg-list.c b/tools/testing/selftests/kvm/get-reg-list.c index a29e548643d11..853cbf470da2f 100644 --- a/tools/testing/selftests/kvm/get-reg-list.c +++ b/tools/testing/selftests/kvm/get-reg-list.c @@ -104,6 +104,7 @@ void __weak print_reg(const char *prefix, __u64 id) printf("\t0x%llx,\n", id); } +#ifdef __aarch64__ static void prepare_vcpu_init(struct vcpu_reg_list *c, struct kvm_vcpu_init *init) { struct vcpu_reg_sublist *s; @@ -126,6 +127,25 @@ static void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c) } } +static struct kvm_vcpu *vcpu_config_get_vcpu(struct vcpu_reg_list *c, struct kvm_vm *vm) +{ + struct kvm_vcpu_init init = { .target = -1, }; + struct kvm_vcpu *vcpu; + + prepare_vcpu_init(c, &init); + vcpu = __vm_vcpu_add(vm, 0); + aarch64_vcpu_setup(vcpu, &init); + finalize_vcpu(vcpu, c); + + return vcpu; +} +#else +static struct kvm_vcpu *vcpu_config_get_vcpu(struct vcpu_reg_list *c, struct kvm_vm *vm) +{ + return __vm_vcpu_add(vm, 0); +} +#endif + static void check_supported(struct vcpu_reg_list *c) { struct vcpu_reg_sublist *s; @@ -145,7 +165,6 @@ static bool print_filtered; static void run_test(struct vcpu_reg_list *c) { - struct kvm_vcpu_init init = { .target = -1, }; int new_regs = 0, missing_regs = 0, i, n; int failed_get = 0, failed_set = 0, failed_reject = 0; struct kvm_vcpu *vcpu; @@ -155,10 +174,7 @@ static void run_test(struct vcpu_reg_list *c) check_supported(c); vm = vm_create_barebones(); - prepare_vcpu_init(c, &init); - vcpu = __vm_vcpu_add(vm, 0); - aarch64_vcpu_setup(vcpu, &init); - finalize_vcpu(vcpu, c); + vcpu = vcpu_config_get_vcpu(c, vm); reg_list = vcpu_get_reg_list(vcpu); -- GitLab From 90a6bcbc542d0d61f50eeb85952e4fc49dbf3841 Mon Sep 17 00:00:00 2001 From: Haibo Xu Date: Tue, 25 Jul 2023 16:41:34 +0800 Subject: [PATCH 0963/3445] KVM: arm64: selftests: Move reject_set check logic to a function No functional changes. Just move the reject_set check logic to a function so we can check for a specific errno. This is a preparation for support reject_set in riscv. Suggested-by: Andrew Jones Signed-off-by: Haibo Xu Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/aarch64/get-reg-list.c | 5 +++++ tools/testing/selftests/kvm/get-reg-list.c | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index f72f1a522ff4c..f8ebc058b1914 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -79,6 +79,11 @@ bool check_supported_reg(struct kvm_vcpu *vcpu, __u64 reg) return check_supported_feat_reg(vcpu, reg); } +bool check_reject_set(int err) +{ + return err == EPERM; +} + #define REG_MASK (KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_COPROC_MASK) #define CORE_REGS_XX_NR_WORDS 2 diff --git a/tools/testing/selftests/kvm/get-reg-list.c b/tools/testing/selftests/kvm/get-reg-list.c index 853cbf470da2f..1df94e8e9ed5f 100644 --- a/tools/testing/selftests/kvm/get-reg-list.c +++ b/tools/testing/selftests/kvm/get-reg-list.c @@ -104,6 +104,11 @@ void __weak print_reg(const char *prefix, __u64 id) printf("\t0x%llx,\n", id); } +bool __weak check_reject_set(int err) +{ + return true; +} + #ifdef __aarch64__ static void prepare_vcpu_init(struct vcpu_reg_list *c, struct kvm_vcpu_init *init) { @@ -222,7 +227,7 @@ static void run_test(struct vcpu_reg_list *c) if (s->rejects_set && find_reg(s->rejects_set, s->rejects_set_n, reg.id)) { reject_reg = true; ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, ®); - if (ret != -1 || errno != EPERM) { + if (ret != -1 || !check_reject_set(errno)) { printf("%s: Failed to reject (ret=%d, errno=%d) ", config_name(c), ret, errno); print_reg(config_name(c), reg.id); putchar('\n'); -- GitLab From e85660338f2b1f20981f2a343a33db75255942a7 Mon Sep 17 00:00:00 2001 From: Haibo Xu Date: Tue, 25 Jul 2023 16:41:35 +0800 Subject: [PATCH 0964/3445] KVM: arm64: selftests: Move finalize_vcpu back to run_test No functional changes. Just move the finalize_vcpu call back to run_test and do weak function trick to prepare for the opration in riscv. Suggested-by: Andrew Jones Signed-off-by: Haibo Xu Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- .../selftests/kvm/aarch64/get-reg-list.c | 13 +++++++++++ tools/testing/selftests/kvm/get-reg-list.c | 22 +++++-------------- .../selftests/kvm/include/kvm_util_base.h | 3 +++ 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index f8ebc058b1914..709d7d7217603 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -84,6 +84,19 @@ bool check_reject_set(int err) return err == EPERM; } +void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c) +{ + struct vcpu_reg_sublist *s; + int feature; + + for_each_sublist(c, s) { + if (s->finalize) { + feature = s->feature; + vcpu_ioctl(vcpu, KVM_ARM_VCPU_FINALIZE, &feature); + } + } +} + #define REG_MASK (KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_COPROC_MASK) #define CORE_REGS_XX_NR_WORDS 2 diff --git a/tools/testing/selftests/kvm/get-reg-list.c b/tools/testing/selftests/kvm/get-reg-list.c index 1df94e8e9ed5f..43a919f2208ff 100644 --- a/tools/testing/selftests/kvm/get-reg-list.c +++ b/tools/testing/selftests/kvm/get-reg-list.c @@ -34,9 +34,6 @@ static __u64 *blessed_reg, blessed_n; extern struct vcpu_reg_list *vcpu_configs[]; extern int vcpu_configs_n; -#define for_each_sublist(c, s) \ - for ((s) = &(c)->sublists[0]; (s)->regs; ++(s)) - #define for_each_reg(i) \ for ((i) = 0; (i) < reg_list->n; ++(i)) @@ -109,6 +106,10 @@ bool __weak check_reject_set(int err) return true; } +void __weak finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c) +{ +} + #ifdef __aarch64__ static void prepare_vcpu_init(struct vcpu_reg_list *c, struct kvm_vcpu_init *init) { @@ -119,19 +120,6 @@ static void prepare_vcpu_init(struct vcpu_reg_list *c, struct kvm_vcpu_init *ini init->features[s->feature / 32] |= 1 << (s->feature % 32); } -static void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c) -{ - struct vcpu_reg_sublist *s; - int feature; - - for_each_sublist(c, s) { - if (s->finalize) { - feature = s->feature; - vcpu_ioctl(vcpu, KVM_ARM_VCPU_FINALIZE, &feature); - } - } -} - static struct kvm_vcpu *vcpu_config_get_vcpu(struct vcpu_reg_list *c, struct kvm_vm *vm) { struct kvm_vcpu_init init = { .target = -1, }; @@ -140,7 +128,6 @@ static struct kvm_vcpu *vcpu_config_get_vcpu(struct vcpu_reg_list *c, struct kvm prepare_vcpu_init(c, &init); vcpu = __vm_vcpu_add(vm, 0); aarch64_vcpu_setup(vcpu, &init); - finalize_vcpu(vcpu, c); return vcpu; } @@ -180,6 +167,7 @@ static void run_test(struct vcpu_reg_list *c) vm = vm_create_barebones(); vcpu = vcpu_config_get_vcpu(c, vm); + finalize_vcpu(vcpu, c); reg_list = vcpu_get_reg_list(vcpu); diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index b5189c7df4828..bc7c08a09d30a 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -141,6 +141,9 @@ struct vcpu_reg_list { struct vcpu_reg_sublist sublists[]; }; +#define for_each_sublist(c, s) \ + for ((s) = &(c)->sublists[0]; (s)->regs; ++(s)) + #define kvm_for_each_vcpu(vm, i, vcpu) \ for ((i) = 0; (i) <= (vm)->last_vcpu_id; (i)++) \ if (!((vcpu) = vm->vcpus[i])) \ -- GitLab From c47467712e8be10805aed4db5626a39aedc784bb Mon Sep 17 00:00:00 2001 From: Haibo Xu Date: Tue, 25 Jul 2023 16:41:36 +0800 Subject: [PATCH 0965/3445] KVM: selftests: Only do get/set tests on present blessed list Only do the get/set tests on present and blessed registers since we don't know the capabilities of any new ones. Suggested-by: Andrew Jones Signed-off-by: Haibo Xu Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/get-reg-list.c | 29 ++++++++++++++-------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/kvm/get-reg-list.c b/tools/testing/selftests/kvm/get-reg-list.c index 43a919f2208ff..2232620fb7974 100644 --- a/tools/testing/selftests/kvm/get-reg-list.c +++ b/tools/testing/selftests/kvm/get-reg-list.c @@ -50,6 +50,10 @@ extern int vcpu_configs_n; for_each_reg_filtered(i) \ if (!find_reg(blessed_reg, blessed_n, reg_list->reg[i])) +#define for_each_present_blessed_reg(i) \ + for_each_reg(i) \ + if (find_reg(blessed_reg, blessed_n, reg_list->reg[i])) + static const char *config_name(struct vcpu_reg_list *c) { struct vcpu_reg_sublist *s; @@ -183,6 +187,16 @@ static void run_test(struct vcpu_reg_list *c) return; } + for_each_sublist(c, s) + blessed_n += s->regs_n; + blessed_reg = calloc(blessed_n, sizeof(__u64)); + + n = 0; + for_each_sublist(c, s) { + for (i = 0; i < s->regs_n; ++i) + blessed_reg[n++] = s->regs[i]; + } + /* * We only test that we can get the register and then write back the * same value. Some registers may allow other values to be written @@ -192,8 +206,11 @@ static void run_test(struct vcpu_reg_list *c) * be written need to have the other values tested, then we should * create a new set of tests for those in a new independent test * executable. + * + * Only do the get/set tests on present, blessed list registers, + * since we don't know the capabilities of any new registers. */ - for_each_reg(i) { + for_each_present_blessed_reg(i) { uint8_t addr[2048 / 8]; struct kvm_one_reg reg = { .id = reg_list->reg[i], @@ -236,16 +253,6 @@ static void run_test(struct vcpu_reg_list *c) } } - for_each_sublist(c, s) - blessed_n += s->regs_n; - blessed_reg = calloc(blessed_n, sizeof(__u64)); - - n = 0; - for_each_sublist(c, s) { - for (i = 0; i < s->regs_n; ++i) - blessed_reg[n++] = s->regs[i]; - } - for_each_new_reg(i) ++new_regs; -- GitLab From cbc0daa67c62bcfeb45cccfc821216549566fb40 Mon Sep 17 00:00:00 2001 From: Haibo Xu Date: Tue, 25 Jul 2023 16:41:37 +0800 Subject: [PATCH 0966/3445] KVM: selftests: Add skip_set facility to get_reg_list test Add new skips_set members to vcpu_reg_sublist so as to skip set operation on some registers. Suggested-by: Andrew Jones Signed-off-by: Haibo Xu Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/get-reg-list.c | 20 +++++++++++++------ .../selftests/kvm/include/kvm_util_base.h | 2 ++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/kvm/get-reg-list.c b/tools/testing/selftests/kvm/get-reg-list.c index 2232620fb7974..be7bf52244347 100644 --- a/tools/testing/selftests/kvm/get-reg-list.c +++ b/tools/testing/selftests/kvm/get-reg-list.c @@ -163,6 +163,7 @@ static void run_test(struct vcpu_reg_list *c) { int new_regs = 0, missing_regs = 0, i, n; int failed_get = 0, failed_set = 0, failed_reject = 0; + int skipped_set = 0; struct kvm_vcpu *vcpu; struct kvm_vm *vm; struct vcpu_reg_sublist *s; @@ -216,7 +217,7 @@ static void run_test(struct vcpu_reg_list *c) .id = reg_list->reg[i], .addr = (__u64)&addr, }; - bool reject_reg = false; + bool reject_reg = false, skip_reg = false; int ret; ret = __vcpu_get_reg(vcpu, reg_list->reg[i], &addr); @@ -227,8 +228,8 @@ static void run_test(struct vcpu_reg_list *c) ++failed_get; } - /* rejects_set registers are rejected after KVM_ARM_VCPU_FINALIZE */ for_each_sublist(c, s) { + /* rejects_set registers are rejected for set operation */ if (s->rejects_set && find_reg(s->rejects_set, s->rejects_set_n, reg.id)) { reject_reg = true; ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, ®); @@ -240,9 +241,16 @@ static void run_test(struct vcpu_reg_list *c) } break; } + + /* skips_set registers are skipped for set operation */ + if (s->skips_set && find_reg(s->skips_set, s->skips_set_n, reg.id)) { + skip_reg = true; + ++skipped_set; + break; + } } - if (!reject_reg) { + if (!reject_reg && !skip_reg) { ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, ®); if (ret) { printf("%s: Failed to set ", config_name(c)); @@ -287,9 +295,9 @@ static void run_test(struct vcpu_reg_list *c) } TEST_ASSERT(!missing_regs && !failed_get && !failed_set && !failed_reject, - "%s: There are %d missing registers; " - "%d registers failed get; %d registers failed set; %d registers failed reject", - config_name(c), missing_regs, failed_get, failed_set, failed_reject); + "%s: There are %d missing registers; %d registers failed get; " + "%d registers failed set; %d registers failed reject; %d registers skipped set", + config_name(c), missing_regs, failed_get, failed_set, failed_reject, skipped_set); pr_info("%s: PASS\n", config_name(c)); blessed_n = 0; diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index bc7c08a09d30a..a18db6a7b3cf4 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -134,6 +134,8 @@ struct vcpu_reg_sublist { __u64 regs_n; __u64 *rejects_set; __u64 rejects_set_n; + __u64 *skips_set; + __u64 skips_set_n; }; struct vcpu_reg_list { -- GitLab From 031f9efafc08d68b1b672e83ee73f6ea5c69c2ef Mon Sep 17 00:00:00 2001 From: Haibo Xu Date: Tue, 25 Jul 2023 16:41:38 +0800 Subject: [PATCH 0967/3445] KVM: riscv: Add KVM_GET_REG_LIST API support KVM_GET_REG_LIST API will return all registers that are available to KVM_GET/SET_ONE_REG APIs. It's very useful to identify some platform regression issue during VM migration. Since this API was already supported on arm64, it is straightforward to enable it on riscv with similar code structure. Signed-off-by: Haibo Xu Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- Documentation/virt/kvm/api.rst | 2 +- arch/riscv/include/asm/kvm_host.h | 3 + arch/riscv/kvm/vcpu.c | 18 ++ arch/riscv/kvm/vcpu_onereg.c | 366 ++++++++++++++++++++++++++++++ 4 files changed, 388 insertions(+), 1 deletion(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 3249fb56cc696..660d9ca7a251d 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -3501,7 +3501,7 @@ VCPU matching underlying host. --------------------- :Capability: basic -:Architectures: arm64, mips +:Architectures: arm64, mips, riscv :Type: vcpu ioctl :Parameters: struct kvm_reg_list (in/out) :Returns: 0 on success; -1 on error diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h index 55bc7bdbff486..1ebf20dfbaa69 100644 --- a/arch/riscv/include/asm/kvm_host.h +++ b/arch/riscv/include/asm/kvm_host.h @@ -338,6 +338,9 @@ int kvm_riscv_vcpu_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, void __kvm_riscv_switch_to(struct kvm_vcpu_arch *vcpu_arch); void kvm_riscv_vcpu_setup_isa(struct kvm_vcpu *vcpu); +unsigned long kvm_riscv_vcpu_num_regs(struct kvm_vcpu *vcpu); +int kvm_riscv_vcpu_copy_reg_indices(struct kvm_vcpu *vcpu, + u64 __user *uindices); int kvm_riscv_vcpu_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); int kvm_riscv_vcpu_set_reg(struct kvm_vcpu *vcpu, diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c index 452d6548e9512..82229db1ce73f 100644 --- a/arch/riscv/kvm/vcpu.c +++ b/arch/riscv/kvm/vcpu.c @@ -254,6 +254,24 @@ long kvm_arch_vcpu_ioctl(struct file *filp, r = kvm_riscv_vcpu_get_reg(vcpu, ®); break; } + case KVM_GET_REG_LIST: { + struct kvm_reg_list __user *user_list = argp; + struct kvm_reg_list reg_list; + unsigned int n; + + r = -EFAULT; + if (copy_from_user(®_list, user_list, sizeof(reg_list))) + break; + n = reg_list.n; + reg_list.n = kvm_riscv_vcpu_num_regs(vcpu); + if (copy_to_user(user_list, ®_list, sizeof(reg_list))) + break; + r = -E2BIG; + if (n < reg_list.n) + break; + r = kvm_riscv_vcpu_copy_reg_indices(vcpu, user_list->reg); + break; + } default: break; } diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index 9fee1c176fbb7..1b7e9fa265cbb 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -622,6 +622,372 @@ static int kvm_riscv_vcpu_set_reg_isa_ext(struct kvm_vcpu *vcpu, return 0; } +static int copy_config_reg_indices(const struct kvm_vcpu *vcpu, + u64 __user *uindices) +{ + int n = 0; + + for (int i = 0; i < sizeof(struct kvm_riscv_config)/sizeof(unsigned long); + i++) { + u64 size; + u64 reg; + + /* + * Avoid reporting config reg if the corresponding extension + * was not available. + */ + if (i == KVM_REG_RISCV_CONFIG_REG(zicbom_block_size) && + !riscv_isa_extension_available(vcpu->arch.isa, ZICBOM)) + continue; + else if (i == KVM_REG_RISCV_CONFIG_REG(zicboz_block_size) && + !riscv_isa_extension_available(vcpu->arch.isa, ZICBOZ)) + continue; + + size = IS_ENABLED(CONFIG_32BIT) ? KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64; + reg = KVM_REG_RISCV | size | KVM_REG_RISCV_CONFIG | i; + + if (uindices) { + if (put_user(reg, uindices)) + return -EFAULT; + uindices++; + } + + n++; + } + + return n; +} + +static unsigned long num_config_regs(const struct kvm_vcpu *vcpu) +{ + return copy_config_reg_indices(vcpu, NULL); +} + +static inline unsigned long num_core_regs(void) +{ + return sizeof(struct kvm_riscv_core) / sizeof(unsigned long); +} + +static int copy_core_reg_indices(u64 __user *uindices) +{ + int n = num_core_regs(); + + for (int i = 0; i < n; i++) { + u64 size = IS_ENABLED(CONFIG_32BIT) ? + KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64; + u64 reg = KVM_REG_RISCV | size | KVM_REG_RISCV_CORE | i; + + if (uindices) { + if (put_user(reg, uindices)) + return -EFAULT; + uindices++; + } + } + + return n; +} + +static inline unsigned long num_csr_regs(const struct kvm_vcpu *vcpu) +{ + unsigned long n = sizeof(struct kvm_riscv_csr) / sizeof(unsigned long); + + if (riscv_isa_extension_available(vcpu->arch.isa, SSAIA)) + n += sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long); + + return n; +} + +static int copy_csr_reg_indices(const struct kvm_vcpu *vcpu, + u64 __user *uindices) +{ + int n1 = sizeof(struct kvm_riscv_csr) / sizeof(unsigned long); + int n2 = 0; + + /* copy general csr regs */ + for (int i = 0; i < n1; i++) { + u64 size = IS_ENABLED(CONFIG_32BIT) ? + KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64; + u64 reg = KVM_REG_RISCV | size | KVM_REG_RISCV_CSR | + KVM_REG_RISCV_CSR_GENERAL | i; + + if (uindices) { + if (put_user(reg, uindices)) + return -EFAULT; + uindices++; + } + } + + /* copy AIA csr regs */ + if (riscv_isa_extension_available(vcpu->arch.isa, SSAIA)) { + n2 = sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long); + + for (int i = 0; i < n2; i++) { + u64 size = IS_ENABLED(CONFIG_32BIT) ? + KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64; + u64 reg = KVM_REG_RISCV | size | KVM_REG_RISCV_CSR | + KVM_REG_RISCV_CSR_AIA | i; + + if (uindices) { + if (put_user(reg, uindices)) + return -EFAULT; + uindices++; + } + } + } + + return n1 + n2; +} + +static inline unsigned long num_timer_regs(void) +{ + return sizeof(struct kvm_riscv_timer) / sizeof(u64); +} + +static int copy_timer_reg_indices(u64 __user *uindices) +{ + int n = num_timer_regs(); + + for (int i = 0; i < n; i++) { + u64 reg = KVM_REG_RISCV | KVM_REG_SIZE_U64 | + KVM_REG_RISCV_TIMER | i; + + if (uindices) { + if (put_user(reg, uindices)) + return -EFAULT; + uindices++; + } + } + + return n; +} + +static inline unsigned long num_fp_f_regs(const struct kvm_vcpu *vcpu) +{ + const struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; + + if (riscv_isa_extension_available(vcpu->arch.isa, f)) + return sizeof(cntx->fp.f) / sizeof(u32); + else + return 0; +} + +static int copy_fp_f_reg_indices(const struct kvm_vcpu *vcpu, + u64 __user *uindices) +{ + int n = num_fp_f_regs(vcpu); + + for (int i = 0; i < n; i++) { + u64 reg = KVM_REG_RISCV | KVM_REG_SIZE_U32 | + KVM_REG_RISCV_FP_F | i; + + if (uindices) { + if (put_user(reg, uindices)) + return -EFAULT; + uindices++; + } + } + + return n; +} + +static inline unsigned long num_fp_d_regs(const struct kvm_vcpu *vcpu) +{ + const struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; + + if (riscv_isa_extension_available(vcpu->arch.isa, d)) + return sizeof(cntx->fp.d.f) / sizeof(u64) + 1; + else + return 0; +} + +static int copy_fp_d_reg_indices(const struct kvm_vcpu *vcpu, + u64 __user *uindices) +{ + int i; + int n = num_fp_d_regs(vcpu); + u64 reg; + + /* copy fp.d.f indices */ + for (i = 0; i < n-1; i++) { + reg = KVM_REG_RISCV | KVM_REG_SIZE_U64 | + KVM_REG_RISCV_FP_D | i; + + if (uindices) { + if (put_user(reg, uindices)) + return -EFAULT; + uindices++; + } + } + + /* copy fp.d.fcsr indices */ + reg = KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_D | i; + if (uindices) { + if (put_user(reg, uindices)) + return -EFAULT; + uindices++; + } + + return n; +} + +static int copy_isa_ext_reg_indices(const struct kvm_vcpu *vcpu, + u64 __user *uindices) +{ + unsigned int n = 0; + unsigned long isa_ext; + + for (int i = 0; i < KVM_RISCV_ISA_EXT_MAX; i++) { + u64 size = IS_ENABLED(CONFIG_32BIT) ? + KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64; + u64 reg = KVM_REG_RISCV | size | KVM_REG_RISCV_ISA_EXT | i; + + isa_ext = kvm_isa_ext_arr[i]; + if (!__riscv_isa_extension_available(vcpu->arch.isa, isa_ext)) + continue; + + if (uindices) { + if (put_user(reg, uindices)) + return -EFAULT; + uindices++; + } + + n++; + } + + return n; +} + +static inline unsigned long num_isa_ext_regs(const struct kvm_vcpu *vcpu) +{ + return copy_isa_ext_reg_indices(vcpu, NULL);; +} + +static inline unsigned long num_sbi_ext_regs(void) +{ + /* + * number of KVM_REG_RISCV_SBI_SINGLE + + * 2 x (number of KVM_REG_RISCV_SBI_MULTI) + */ + return KVM_RISCV_SBI_EXT_MAX + 2*(KVM_REG_RISCV_SBI_MULTI_REG_LAST+1); +} + +static int copy_sbi_ext_reg_indices(u64 __user *uindices) +{ + int n; + + /* copy KVM_REG_RISCV_SBI_SINGLE */ + n = KVM_RISCV_SBI_EXT_MAX; + for (int i = 0; i < n; i++) { + u64 size = IS_ENABLED(CONFIG_32BIT) ? + KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64; + u64 reg = KVM_REG_RISCV | size | KVM_REG_RISCV_SBI_EXT | + KVM_REG_RISCV_SBI_SINGLE | i; + + if (uindices) { + if (put_user(reg, uindices)) + return -EFAULT; + uindices++; + } + } + + /* copy KVM_REG_RISCV_SBI_MULTI */ + n = KVM_REG_RISCV_SBI_MULTI_REG_LAST + 1; + for (int i = 0; i < n; i++) { + u64 size = IS_ENABLED(CONFIG_32BIT) ? + KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64; + u64 reg = KVM_REG_RISCV | size | KVM_REG_RISCV_SBI_EXT | + KVM_REG_RISCV_SBI_MULTI_EN | i; + + if (uindices) { + if (put_user(reg, uindices)) + return -EFAULT; + uindices++; + } + + reg = KVM_REG_RISCV | size | KVM_REG_RISCV_SBI_EXT | + KVM_REG_RISCV_SBI_MULTI_DIS | i; + + if (uindices) { + if (put_user(reg, uindices)) + return -EFAULT; + uindices++; + } + } + + return num_sbi_ext_regs(); +} + +/* + * kvm_riscv_vcpu_num_regs - how many registers do we present via KVM_GET/SET_ONE_REG + * + * This is for all registers. + */ +unsigned long kvm_riscv_vcpu_num_regs(struct kvm_vcpu *vcpu) +{ + unsigned long res = 0; + + res += num_config_regs(vcpu); + res += num_core_regs(); + res += num_csr_regs(vcpu); + res += num_timer_regs(); + res += num_fp_f_regs(vcpu); + res += num_fp_d_regs(vcpu); + res += num_isa_ext_regs(vcpu); + res += num_sbi_ext_regs(); + + return res; +} + +/* + * kvm_riscv_vcpu_copy_reg_indices - get indices of all registers. + */ +int kvm_riscv_vcpu_copy_reg_indices(struct kvm_vcpu *vcpu, + u64 __user *uindices) +{ + int ret; + + ret = copy_config_reg_indices(vcpu, uindices); + if (ret < 0) + return ret; + uindices += ret; + + ret = copy_core_reg_indices(uindices); + if (ret < 0) + return ret; + uindices += ret; + + ret = copy_csr_reg_indices(vcpu, uindices); + if (ret < 0) + return ret; + uindices += ret; + + ret = copy_timer_reg_indices(uindices); + if (ret < 0) + return ret; + uindices += ret; + + ret = copy_fp_f_reg_indices(vcpu, uindices); + if (ret < 0) + return ret; + uindices += ret; + + ret = copy_fp_d_reg_indices(vcpu, uindices); + if (ret < 0) + return ret; + uindices += ret; + + ret = copy_isa_ext_reg_indices(vcpu, uindices); + if (ret < 0) + return ret; + uindices += ret; + + ret = copy_sbi_ext_reg_indices(uindices); + if (ret < 0) + return ret; + + return 0; +} + int kvm_riscv_vcpu_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) { -- GitLab From 477069398ed6e0498ee243e799cb6c68baf6ccb8 Mon Sep 17 00:00:00 2001 From: Haibo Xu Date: Tue, 25 Jul 2023 16:41:39 +0800 Subject: [PATCH 0968/3445] KVM: riscv: selftests: Add get-reg-list test get-reg-list test is used to check for KVM registers regressions during VM migration which happens when destination host kernel missing registers that the source host kernel has. The blessed list registers was created by running on v6.5-rc3 Signed-off-by: Haibo Xu Reviewed-by: Andrew Jones Signed-off-by: Anup Patel --- tools/testing/selftests/kvm/Makefile | 1 + .../selftests/kvm/include/riscv/processor.h | 3 + .../selftests/kvm/riscv/get-reg-list.c | 872 ++++++++++++++++++ 3 files changed, 876 insertions(+) create mode 100644 tools/testing/selftests/kvm/riscv/get-reg-list.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 95f180e711d5a..72ba48fcdc66a 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -176,6 +176,7 @@ TEST_GEN_PROGS_s390x += kvm_binary_stats_test TEST_GEN_PROGS_riscv += demand_paging_test TEST_GEN_PROGS_riscv += dirty_log_test +TEST_GEN_PROGS_riscv += get-reg-list TEST_GEN_PROGS_riscv += kvm_create_max_vcpus TEST_GEN_PROGS_riscv += kvm_page_table_test TEST_GEN_PROGS_riscv += set_memory_region_test diff --git a/tools/testing/selftests/kvm/include/riscv/processor.h b/tools/testing/selftests/kvm/include/riscv/processor.h index d00d213c3805e..5b62a3d2aa9b5 100644 --- a/tools/testing/selftests/kvm/include/riscv/processor.h +++ b/tools/testing/selftests/kvm/include/riscv/processor.h @@ -38,6 +38,9 @@ static inline uint64_t __kvm_reg_id(uint64_t type, uint64_t idx, KVM_REG_RISCV_TIMER_REG(name), \ KVM_REG_SIZE_U64) +#define RISCV_ISA_EXT_REG(idx) __kvm_reg_id(KVM_REG_RISCV_ISA_EXT, \ + idx, KVM_REG_SIZE_ULONG) + /* L3 index Bit[47:39] */ #define PGTBL_L3_INDEX_MASK 0x0000FF8000000000ULL #define PGTBL_L3_INDEX_SHIFT 39 diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c new file mode 100644 index 0000000000000..d8ecacd03ecfb --- /dev/null +++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c @@ -0,0 +1,872 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Check for KVM_GET_REG_LIST regressions. + * + * Copyright (c) 2023 Intel Corporation + * + */ +#include +#include "kvm_util.h" +#include "test_util.h" +#include "processor.h" + +#define REG_MASK (KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK) + +bool filter_reg(__u64 reg) +{ + /* + * Some ISA extensions are optional and not present on all host, + * but they can't be disabled through ISA_EXT registers when present. + * So, to make life easy, just filtering out these kind of registers. + */ + switch (reg & ~REG_MASK) { + case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SSTC: + case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SVINVAL: + case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZIHINTPAUSE: + case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZBB: + case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SSAIA: + case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZBA: + case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZBS: + case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICNTR: + case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICSR: + case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZIFENCEI: + case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZIHPM: + return true; + default: + break; + } + + return false; +} + +bool check_reject_set(int err) +{ + return err == EINVAL; +} + +static inline bool vcpu_has_ext(struct kvm_vcpu *vcpu, int ext) +{ + int ret; + unsigned long value; + + ret = __vcpu_get_reg(vcpu, RISCV_ISA_EXT_REG(ext), &value); + if (ret) { + printf("Failed to get ext %d", ext); + return false; + } + + return !!value; +} + +void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c) +{ + struct vcpu_reg_sublist *s; + + /* + * Disable all extensions which were enabled by default + * if they were available in the risc-v host. + */ + for (int i = 0; i < KVM_RISCV_ISA_EXT_MAX; i++) + __vcpu_set_reg(vcpu, RISCV_ISA_EXT_REG(i), 0); + + for_each_sublist(c, s) { + if (!s->feature) + continue; + + /* Try to enable the desired extension */ + __vcpu_set_reg(vcpu, RISCV_ISA_EXT_REG(s->feature), 1); + + /* Double check whether the desired extension was enabled */ + __TEST_REQUIRE(vcpu_has_ext(vcpu, s->feature), + "%s not available, skipping tests\n", s->name); + } +} + +static const char *config_id_to_str(__u64 id) +{ + /* reg_off is the offset into struct kvm_riscv_config */ + __u64 reg_off = id & ~(REG_MASK | KVM_REG_RISCV_CONFIG); + + switch (reg_off) { + case KVM_REG_RISCV_CONFIG_REG(isa): + return "KVM_REG_RISCV_CONFIG_REG(isa)"; + case KVM_REG_RISCV_CONFIG_REG(zicbom_block_size): + return "KVM_REG_RISCV_CONFIG_REG(zicbom_block_size)"; + case KVM_REG_RISCV_CONFIG_REG(zicboz_block_size): + return "KVM_REG_RISCV_CONFIG_REG(zicboz_block_size)"; + case KVM_REG_RISCV_CONFIG_REG(mvendorid): + return "KVM_REG_RISCV_CONFIG_REG(mvendorid)"; + case KVM_REG_RISCV_CONFIG_REG(marchid): + return "KVM_REG_RISCV_CONFIG_REG(marchid)"; + case KVM_REG_RISCV_CONFIG_REG(mimpid): + return "KVM_REG_RISCV_CONFIG_REG(mimpid)"; + case KVM_REG_RISCV_CONFIG_REG(satp_mode): + return "KVM_REG_RISCV_CONFIG_REG(satp_mode)"; + } + + /* + * Config regs would grow regularly with new pseudo reg added, so + * just show raw id to indicate a new pseudo config reg. + */ + return strdup_printf("KVM_REG_RISCV_CONFIG_REG(%lld) /* UNKNOWN */", reg_off); +} + +static const char *core_id_to_str(const char *prefix, __u64 id) +{ + /* reg_off is the offset into struct kvm_riscv_core */ + __u64 reg_off = id & ~(REG_MASK | KVM_REG_RISCV_CORE); + + switch (reg_off) { + case KVM_REG_RISCV_CORE_REG(regs.pc): + return "KVM_REG_RISCV_CORE_REG(regs.pc)"; + case KVM_REG_RISCV_CORE_REG(regs.ra): + return "KVM_REG_RISCV_CORE_REG(regs.ra)"; + case KVM_REG_RISCV_CORE_REG(regs.sp): + return "KVM_REG_RISCV_CORE_REG(regs.sp)"; + case KVM_REG_RISCV_CORE_REG(regs.gp): + return "KVM_REG_RISCV_CORE_REG(regs.gp)"; + case KVM_REG_RISCV_CORE_REG(regs.tp): + return "KVM_REG_RISCV_CORE_REG(regs.tp)"; + case KVM_REG_RISCV_CORE_REG(regs.t0) ... KVM_REG_RISCV_CORE_REG(regs.t2): + return strdup_printf("KVM_REG_RISCV_CORE_REG(regs.t%lld)", + reg_off - KVM_REG_RISCV_CORE_REG(regs.t0)); + case KVM_REG_RISCV_CORE_REG(regs.s0) ... KVM_REG_RISCV_CORE_REG(regs.s1): + return strdup_printf("KVM_REG_RISCV_CORE_REG(regs.s%lld)", + reg_off - KVM_REG_RISCV_CORE_REG(regs.s0)); + case KVM_REG_RISCV_CORE_REG(regs.a0) ... KVM_REG_RISCV_CORE_REG(regs.a7): + return strdup_printf("KVM_REG_RISCV_CORE_REG(regs.a%lld)", + reg_off - KVM_REG_RISCV_CORE_REG(regs.a0)); + case KVM_REG_RISCV_CORE_REG(regs.s2) ... KVM_REG_RISCV_CORE_REG(regs.s11): + return strdup_printf("KVM_REG_RISCV_CORE_REG(regs.s%lld)", + reg_off - KVM_REG_RISCV_CORE_REG(regs.s2) + 2); + case KVM_REG_RISCV_CORE_REG(regs.t3) ... KVM_REG_RISCV_CORE_REG(regs.t6): + return strdup_printf("KVM_REG_RISCV_CORE_REG(regs.t%lld)", + reg_off - KVM_REG_RISCV_CORE_REG(regs.t3) + 3); + case KVM_REG_RISCV_CORE_REG(mode): + return "KVM_REG_RISCV_CORE_REG(mode)"; + } + + TEST_FAIL("%s: Unknown core reg id: 0x%llx", prefix, id); + return NULL; +} + +#define RISCV_CSR_GENERAL(csr) \ + "KVM_REG_RISCV_CSR_GENERAL | KVM_REG_RISCV_CSR_REG(" #csr ")" +#define RISCV_CSR_AIA(csr) \ + "KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_REG(" #csr ")" + +static const char *general_csr_id_to_str(__u64 reg_off) +{ + /* reg_off is the offset into struct kvm_riscv_csr */ + switch (reg_off) { + case KVM_REG_RISCV_CSR_REG(sstatus): + return RISCV_CSR_GENERAL(sstatus); + case KVM_REG_RISCV_CSR_REG(sie): + return RISCV_CSR_GENERAL(sie); + case KVM_REG_RISCV_CSR_REG(stvec): + return RISCV_CSR_GENERAL(stvec); + case KVM_REG_RISCV_CSR_REG(sscratch): + return RISCV_CSR_GENERAL(sscratch); + case KVM_REG_RISCV_CSR_REG(sepc): + return RISCV_CSR_GENERAL(sepc); + case KVM_REG_RISCV_CSR_REG(scause): + return RISCV_CSR_GENERAL(scause); + case KVM_REG_RISCV_CSR_REG(stval): + return RISCV_CSR_GENERAL(stval); + case KVM_REG_RISCV_CSR_REG(sip): + return RISCV_CSR_GENERAL(sip); + case KVM_REG_RISCV_CSR_REG(satp): + return RISCV_CSR_GENERAL(satp); + case KVM_REG_RISCV_CSR_REG(scounteren): + return RISCV_CSR_GENERAL(scounteren); + } + + TEST_FAIL("Unknown general csr reg: 0x%llx", reg_off); + return NULL; +} + +static const char *aia_csr_id_to_str(__u64 reg_off) +{ + /* reg_off is the offset into struct kvm_riscv_aia_csr */ + switch (reg_off) { + case KVM_REG_RISCV_CSR_AIA_REG(siselect): + return RISCV_CSR_AIA(siselect); + case KVM_REG_RISCV_CSR_AIA_REG(iprio1): + return RISCV_CSR_AIA(iprio1); + case KVM_REG_RISCV_CSR_AIA_REG(iprio2): + return RISCV_CSR_AIA(iprio2); + case KVM_REG_RISCV_CSR_AIA_REG(sieh): + return RISCV_CSR_AIA(sieh); + case KVM_REG_RISCV_CSR_AIA_REG(siph): + return RISCV_CSR_AIA(siph); + case KVM_REG_RISCV_CSR_AIA_REG(iprio1h): + return RISCV_CSR_AIA(iprio1h); + case KVM_REG_RISCV_CSR_AIA_REG(iprio2h): + return RISCV_CSR_AIA(iprio2h); + } + + TEST_FAIL("Unknown aia csr reg: 0x%llx", reg_off); + return NULL; +} + +static const char *csr_id_to_str(const char *prefix, __u64 id) +{ + __u64 reg_off = id & ~(REG_MASK | KVM_REG_RISCV_CSR); + __u64 reg_subtype = reg_off & KVM_REG_RISCV_SUBTYPE_MASK; + + reg_off &= ~KVM_REG_RISCV_SUBTYPE_MASK; + + switch (reg_subtype) { + case KVM_REG_RISCV_CSR_GENERAL: + return general_csr_id_to_str(reg_off); + case KVM_REG_RISCV_CSR_AIA: + return aia_csr_id_to_str(reg_off); + } + + TEST_FAIL("%s: Unknown csr subtype: 0x%llx", prefix, reg_subtype); + return NULL; +} + +static const char *timer_id_to_str(const char *prefix, __u64 id) +{ + /* reg_off is the offset into struct kvm_riscv_timer */ + __u64 reg_off = id & ~(REG_MASK | KVM_REG_RISCV_TIMER); + + switch (reg_off) { + case KVM_REG_RISCV_TIMER_REG(frequency): + return "KVM_REG_RISCV_TIMER_REG(frequency)"; + case KVM_REG_RISCV_TIMER_REG(time): + return "KVM_REG_RISCV_TIMER_REG(time)"; + case KVM_REG_RISCV_TIMER_REG(compare): + return "KVM_REG_RISCV_TIMER_REG(compare)"; + case KVM_REG_RISCV_TIMER_REG(state): + return "KVM_REG_RISCV_TIMER_REG(state)"; + } + + TEST_FAIL("%s: Unknown timer reg id: 0x%llx", prefix, id); + return NULL; +} + +static const char *fp_f_id_to_str(const char *prefix, __u64 id) +{ + /* reg_off is the offset into struct __riscv_f_ext_state */ + __u64 reg_off = id & ~(REG_MASK | KVM_REG_RISCV_FP_F); + + switch (reg_off) { + case KVM_REG_RISCV_FP_F_REG(f[0]) ... + KVM_REG_RISCV_FP_F_REG(f[31]): + return strdup_printf("KVM_REG_RISCV_FP_F_REG(f[%lld])", reg_off); + case KVM_REG_RISCV_FP_F_REG(fcsr): + return "KVM_REG_RISCV_FP_F_REG(fcsr)"; + } + + TEST_FAIL("%s: Unknown fp_f reg id: 0x%llx", prefix, id); + return NULL; +} + +static const char *fp_d_id_to_str(const char *prefix, __u64 id) +{ + /* reg_off is the offset into struct __riscv_d_ext_state */ + __u64 reg_off = id & ~(REG_MASK | KVM_REG_RISCV_FP_D); + + switch (reg_off) { + case KVM_REG_RISCV_FP_D_REG(f[0]) ... + KVM_REG_RISCV_FP_D_REG(f[31]): + return strdup_printf("KVM_REG_RISCV_FP_D_REG(f[%lld])", reg_off); + case KVM_REG_RISCV_FP_D_REG(fcsr): + return "KVM_REG_RISCV_FP_D_REG(fcsr)"; + } + + TEST_FAIL("%s: Unknown fp_d reg id: 0x%llx", prefix, id); + return NULL; +} + +static const char *isa_ext_id_to_str(__u64 id) +{ + /* reg_off is the offset into unsigned long kvm_isa_ext_arr[] */ + __u64 reg_off = id & ~(REG_MASK | KVM_REG_RISCV_ISA_EXT); + + static const char * const kvm_isa_ext_reg_name[] = { + "KVM_RISCV_ISA_EXT_A", + "KVM_RISCV_ISA_EXT_C", + "KVM_RISCV_ISA_EXT_D", + "KVM_RISCV_ISA_EXT_F", + "KVM_RISCV_ISA_EXT_H", + "KVM_RISCV_ISA_EXT_I", + "KVM_RISCV_ISA_EXT_M", + "KVM_RISCV_ISA_EXT_SVPBMT", + "KVM_RISCV_ISA_EXT_SSTC", + "KVM_RISCV_ISA_EXT_SVINVAL", + "KVM_RISCV_ISA_EXT_ZIHINTPAUSE", + "KVM_RISCV_ISA_EXT_ZICBOM", + "KVM_RISCV_ISA_EXT_ZICBOZ", + "KVM_RISCV_ISA_EXT_ZBB", + "KVM_RISCV_ISA_EXT_SSAIA", + "KVM_RISCV_ISA_EXT_V", + "KVM_RISCV_ISA_EXT_SVNAPOT", + "KVM_RISCV_ISA_EXT_ZBA", + "KVM_RISCV_ISA_EXT_ZBS", + "KVM_RISCV_ISA_EXT_ZICNTR", + "KVM_RISCV_ISA_EXT_ZICSR", + "KVM_RISCV_ISA_EXT_ZIFENCEI", + "KVM_RISCV_ISA_EXT_ZIHPM", + }; + + if (reg_off >= ARRAY_SIZE(kvm_isa_ext_reg_name)) { + /* + * isa_ext regs would grow regularly with new isa extension added, so + * just show "reg" to indicate a new extension. + */ + return strdup_printf("%lld /* UNKNOWN */", reg_off); + } + + return kvm_isa_ext_reg_name[reg_off]; +} + +static const char *sbi_ext_single_id_to_str(__u64 reg_off) +{ + /* reg_off is KVM_RISCV_SBI_EXT_ID */ + static const char * const kvm_sbi_ext_reg_name[] = { + "KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_V01", + "KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_TIME", + "KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_IPI", + "KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_RFENCE", + "KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_SRST", + "KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_HSM", + "KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_PMU", + "KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_EXPERIMENTAL", + "KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_VENDOR", + }; + + if (reg_off >= ARRAY_SIZE(kvm_sbi_ext_reg_name)) { + /* + * sbi_ext regs would grow regularly with new sbi extension added, so + * just show "reg" to indicate a new extension. + */ + return strdup_printf("KVM_REG_RISCV_SBI_SINGLE | %lld /* UNKNOWN */", reg_off); + } + + return kvm_sbi_ext_reg_name[reg_off]; +} + +static const char *sbi_ext_multi_id_to_str(__u64 reg_subtype, __u64 reg_off) +{ + if (reg_off > KVM_REG_RISCV_SBI_MULTI_REG_LAST) { + /* + * sbi_ext regs would grow regularly with new sbi extension added, so + * just show "reg" to indicate a new extension. + */ + return strdup_printf("%lld /* UNKNOWN */", reg_off); + } + + switch (reg_subtype) { + case KVM_REG_RISCV_SBI_MULTI_EN: + return strdup_printf("KVM_REG_RISCV_SBI_MULTI_EN | %lld", reg_off); + case KVM_REG_RISCV_SBI_MULTI_DIS: + return strdup_printf("KVM_REG_RISCV_SBI_MULTI_DIS | %lld", reg_off); + } + + return NULL; +} + +static const char *sbi_ext_id_to_str(const char *prefix, __u64 id) +{ + __u64 reg_off = id & ~(REG_MASK | KVM_REG_RISCV_SBI_EXT); + __u64 reg_subtype = reg_off & KVM_REG_RISCV_SUBTYPE_MASK; + + reg_off &= ~KVM_REG_RISCV_SUBTYPE_MASK; + + switch (reg_subtype) { + case KVM_REG_RISCV_SBI_SINGLE: + return sbi_ext_single_id_to_str(reg_off); + case KVM_REG_RISCV_SBI_MULTI_EN: + case KVM_REG_RISCV_SBI_MULTI_DIS: + return sbi_ext_multi_id_to_str(reg_subtype, reg_off); + } + + TEST_FAIL("%s: Unknown sbi ext subtype: 0x%llx", prefix, reg_subtype); + return NULL; +} + +void print_reg(const char *prefix, __u64 id) +{ + const char *reg_size = NULL; + + TEST_ASSERT((id & KVM_REG_ARCH_MASK) == KVM_REG_RISCV, + "%s: KVM_REG_RISCV missing in reg id: 0x%llx", prefix, id); + + switch (id & KVM_REG_SIZE_MASK) { + case KVM_REG_SIZE_U32: + reg_size = "KVM_REG_SIZE_U32"; + break; + case KVM_REG_SIZE_U64: + reg_size = "KVM_REG_SIZE_U64"; + break; + case KVM_REG_SIZE_U128: + reg_size = "KVM_REG_SIZE_U128"; + break; + default: + TEST_FAIL("%s: Unexpected reg size: 0x%llx in reg id: 0x%llx", + prefix, (id & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT, id); + } + + switch (id & KVM_REG_RISCV_TYPE_MASK) { + case KVM_REG_RISCV_CONFIG: + printf("\tKVM_REG_RISCV | %s | KVM_REG_RISCV_CONFIG | %s,\n", + reg_size, config_id_to_str(id)); + break; + case KVM_REG_RISCV_CORE: + printf("\tKVM_REG_RISCV | %s | KVM_REG_RISCV_CORE | %s,\n", + reg_size, core_id_to_str(prefix, id)); + break; + case KVM_REG_RISCV_CSR: + printf("\tKVM_REG_RISCV | %s | KVM_REG_RISCV_CSR | %s,\n", + reg_size, csr_id_to_str(prefix, id)); + break; + case KVM_REG_RISCV_TIMER: + printf("\tKVM_REG_RISCV | %s | KVM_REG_RISCV_TIMER | %s,\n", + reg_size, timer_id_to_str(prefix, id)); + break; + case KVM_REG_RISCV_FP_F: + printf("\tKVM_REG_RISCV | %s | KVM_REG_RISCV_FP_F | %s,\n", + reg_size, fp_f_id_to_str(prefix, id)); + break; + case KVM_REG_RISCV_FP_D: + printf("\tKVM_REG_RISCV | %s | KVM_REG_RISCV_FP_D | %s,\n", + reg_size, fp_d_id_to_str(prefix, id)); + break; + case KVM_REG_RISCV_ISA_EXT: + printf("\tKVM_REG_RISCV | %s | KVM_REG_RISCV_ISA_EXT | %s,\n", + reg_size, isa_ext_id_to_str(id)); + break; + case KVM_REG_RISCV_SBI_EXT: + printf("\tKVM_REG_RISCV | %s | KVM_REG_RISCV_SBI_EXT | %s,\n", + reg_size, sbi_ext_id_to_str(prefix, id)); + break; + default: + TEST_FAIL("%s: Unexpected reg type: 0x%llx in reg id: 0x%llx", prefix, + (id & KVM_REG_RISCV_TYPE_MASK) >> KVM_REG_RISCV_TYPE_SHIFT, id); + } +} + +/* + * The current blessed list was primed with the output of kernel version + * v6.5-rc3 and then later updated with new registers. + */ +static __u64 base_regs[] = { + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(isa), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(mvendorid), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(marchid), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(mimpid), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(satp_mode), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.pc), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.ra), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.sp), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.gp), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.tp), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.t0), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.t1), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.t2), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.s0), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.s1), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.a0), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.a1), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.a2), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.a3), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.a4), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.a5), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.a6), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.a7), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.s2), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.s3), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.s4), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.s5), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.s6), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.s7), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.s8), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.s9), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.s10), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.s11), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.t3), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.t4), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.t5), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(regs.t6), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CORE | KVM_REG_RISCV_CORE_REG(mode), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_GENERAL | KVM_REG_RISCV_CSR_REG(sstatus), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_GENERAL | KVM_REG_RISCV_CSR_REG(sie), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_GENERAL | KVM_REG_RISCV_CSR_REG(stvec), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_GENERAL | KVM_REG_RISCV_CSR_REG(sscratch), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_GENERAL | KVM_REG_RISCV_CSR_REG(sepc), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_GENERAL | KVM_REG_RISCV_CSR_REG(scause), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_GENERAL | KVM_REG_RISCV_CSR_REG(stval), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_GENERAL | KVM_REG_RISCV_CSR_REG(sip), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_GENERAL | KVM_REG_RISCV_CSR_REG(satp), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_GENERAL | KVM_REG_RISCV_CSR_REG(scounteren), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_TIMER | KVM_REG_RISCV_TIMER_REG(frequency), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_TIMER | KVM_REG_RISCV_TIMER_REG(time), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_TIMER | KVM_REG_RISCV_TIMER_REG(compare), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_TIMER | KVM_REG_RISCV_TIMER_REG(state), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_A, + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_C, + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_I, + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_M, + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_V01, + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_TIME, + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_IPI, + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_RFENCE, + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_SRST, + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_HSM, + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_PMU, + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_EXPERIMENTAL, + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_VENDOR, + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_MULTI_EN | 0, + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_MULTI_DIS | 0, +}; + +/* + * The skips_set list registers that should skip set test. + * - KVM_REG_RISCV_TIMER_REG(state): set would fail if it was not initialized properly. + */ +static __u64 base_skips_set[] = { + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_TIMER | KVM_REG_RISCV_TIMER_REG(state), +}; + +static __u64 h_regs[] = { + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_H, +}; + +static __u64 zicbom_regs[] = { + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(zicbom_block_size), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICBOM, +}; + +static __u64 zicboz_regs[] = { + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(zicboz_block_size), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICBOZ, +}; + +static __u64 svpbmt_regs[] = { + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SVPBMT, +}; + +static __u64 sstc_regs[] = { + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SSTC, +}; + +static __u64 svinval_regs[] = { + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SVINVAL, +}; + +static __u64 zihintpause_regs[] = { + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZIHINTPAUSE, +}; + +static __u64 zba_regs[] = { + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZBA, +}; + +static __u64 zbb_regs[] = { + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZBB, +}; + +static __u64 zbs_regs[] = { + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZBS, +}; + +static __u64 zicntr_regs[] = { + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICNTR, +}; + +static __u64 zicsr_regs[] = { + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICSR, +}; + +static __u64 zifencei_regs[] = { + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZIFENCEI, +}; + +static __u64 zihpm_regs[] = { + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZIHPM, +}; + +static __u64 aia_regs[] = { + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(siselect), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(iprio1), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(iprio2), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(sieh), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(siph), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(iprio1h), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(iprio2h), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SSAIA, +}; + +static __u64 fp_f_regs[] = { + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[0]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[1]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[2]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[3]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[4]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[5]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[6]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[7]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[8]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[9]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[10]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[11]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[12]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[13]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[14]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[15]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[16]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[17]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[18]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[19]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[20]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[21]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[22]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[23]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[24]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[25]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[26]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[27]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[28]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[29]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[30]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[31]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(fcsr), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_F, +}; + +static __u64 fp_d_regs[] = { + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[0]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[1]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[2]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[3]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[4]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[5]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[6]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[7]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[8]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[9]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[10]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[11]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[12]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[13]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[14]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[15]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[16]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[17]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[18]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[19]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[20]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[21]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[22]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[23]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[24]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[25]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[26]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[27]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[28]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[29]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[30]), + KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[31]), + KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(fcsr), + KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_D, +}; + +#define BASE_SUBLIST \ + {"base", .regs = base_regs, .regs_n = ARRAY_SIZE(base_regs), \ + .skips_set = base_skips_set, .skips_set_n = ARRAY_SIZE(base_skips_set),} +#define H_REGS_SUBLIST \ + {"h", .feature = KVM_RISCV_ISA_EXT_H, .regs = h_regs, .regs_n = ARRAY_SIZE(h_regs),} +#define ZICBOM_REGS_SUBLIST \ + {"zicbom", .feature = KVM_RISCV_ISA_EXT_ZICBOM, .regs = zicbom_regs, .regs_n = ARRAY_SIZE(zicbom_regs),} +#define ZICBOZ_REGS_SUBLIST \ + {"zicboz", .feature = KVM_RISCV_ISA_EXT_ZICBOZ, .regs = zicboz_regs, .regs_n = ARRAY_SIZE(zicboz_regs),} +#define SVPBMT_REGS_SUBLIST \ + {"svpbmt", .feature = KVM_RISCV_ISA_EXT_SVPBMT, .regs = svpbmt_regs, .regs_n = ARRAY_SIZE(svpbmt_regs),} +#define SSTC_REGS_SUBLIST \ + {"sstc", .feature = KVM_RISCV_ISA_EXT_SSTC, .regs = sstc_regs, .regs_n = ARRAY_SIZE(sstc_regs),} +#define SVINVAL_REGS_SUBLIST \ + {"svinval", .feature = KVM_RISCV_ISA_EXT_SVINVAL, .regs = svinval_regs, .regs_n = ARRAY_SIZE(svinval_regs),} +#define ZIHINTPAUSE_REGS_SUBLIST \ + {"zihintpause", .feature = KVM_RISCV_ISA_EXT_ZIHINTPAUSE, .regs = zihintpause_regs, .regs_n = ARRAY_SIZE(zihintpause_regs),} +#define ZBA_REGS_SUBLIST \ + {"zba", .feature = KVM_RISCV_ISA_EXT_ZBA, .regs = zba_regs, .regs_n = ARRAY_SIZE(zba_regs),} +#define ZBB_REGS_SUBLIST \ + {"zbb", .feature = KVM_RISCV_ISA_EXT_ZBB, .regs = zbb_regs, .regs_n = ARRAY_SIZE(zbb_regs),} +#define ZBS_REGS_SUBLIST \ + {"zbs", .feature = KVM_RISCV_ISA_EXT_ZBS, .regs = zbs_regs, .regs_n = ARRAY_SIZE(zbs_regs),} +#define ZICNTR_REGS_SUBLIST \ + {"zicntr", .feature = KVM_RISCV_ISA_EXT_ZICNTR, .regs = zicntr_regs, .regs_n = ARRAY_SIZE(zicntr_regs),} +#define ZICSR_REGS_SUBLIST \ + {"zicsr", .feature = KVM_RISCV_ISA_EXT_ZICSR, .regs = zicsr_regs, .regs_n = ARRAY_SIZE(zicsr_regs),} +#define ZIFENCEI_REGS_SUBLIST \ + {"zifencei", .feature = KVM_RISCV_ISA_EXT_ZIFENCEI, .regs = zifencei_regs, .regs_n = ARRAY_SIZE(zifencei_regs),} +#define ZIHPM_REGS_SUBLIST \ + {"zihpm", .feature = KVM_RISCV_ISA_EXT_ZIHPM, .regs = zihpm_regs, .regs_n = ARRAY_SIZE(zihpm_regs),} +#define AIA_REGS_SUBLIST \ + {"aia", .feature = KVM_RISCV_ISA_EXT_SSAIA, .regs = aia_regs, .regs_n = ARRAY_SIZE(aia_regs),} +#define FP_F_REGS_SUBLIST \ + {"fp_f", .feature = KVM_RISCV_ISA_EXT_F, .regs = fp_f_regs, \ + .regs_n = ARRAY_SIZE(fp_f_regs),} +#define FP_D_REGS_SUBLIST \ + {"fp_d", .feature = KVM_RISCV_ISA_EXT_D, .regs = fp_d_regs, \ + .regs_n = ARRAY_SIZE(fp_d_regs),} + +static struct vcpu_reg_list h_config = { + .sublists = { + BASE_SUBLIST, + H_REGS_SUBLIST, + {0}, + }, +}; + +static struct vcpu_reg_list zicbom_config = { + .sublists = { + BASE_SUBLIST, + ZICBOM_REGS_SUBLIST, + {0}, + }, +}; + +static struct vcpu_reg_list zicboz_config = { + .sublists = { + BASE_SUBLIST, + ZICBOZ_REGS_SUBLIST, + {0}, + }, +}; + +static struct vcpu_reg_list svpbmt_config = { + .sublists = { + BASE_SUBLIST, + SVPBMT_REGS_SUBLIST, + {0}, + }, +}; + +static struct vcpu_reg_list sstc_config = { + .sublists = { + BASE_SUBLIST, + SSTC_REGS_SUBLIST, + {0}, + }, +}; + +static struct vcpu_reg_list svinval_config = { + .sublists = { + BASE_SUBLIST, + SVINVAL_REGS_SUBLIST, + {0}, + }, +}; + +static struct vcpu_reg_list zihintpause_config = { + .sublists = { + BASE_SUBLIST, + ZIHINTPAUSE_REGS_SUBLIST, + {0}, + }, +}; + +static struct vcpu_reg_list zba_config = { + .sublists = { + BASE_SUBLIST, + ZBA_REGS_SUBLIST, + {0}, + }, +}; + +static struct vcpu_reg_list zbb_config = { + .sublists = { + BASE_SUBLIST, + ZBB_REGS_SUBLIST, + {0}, + }, +}; + +static struct vcpu_reg_list zbs_config = { + .sublists = { + BASE_SUBLIST, + ZBS_REGS_SUBLIST, + {0}, + }, +}; + +static struct vcpu_reg_list zicntr_config = { + .sublists = { + BASE_SUBLIST, + ZICNTR_REGS_SUBLIST, + {0}, + }, +}; + +static struct vcpu_reg_list zicsr_config = { + .sublists = { + BASE_SUBLIST, + ZICSR_REGS_SUBLIST, + {0}, + }, +}; + +static struct vcpu_reg_list zifencei_config = { + .sublists = { + BASE_SUBLIST, + ZIFENCEI_REGS_SUBLIST, + {0}, + }, +}; + +static struct vcpu_reg_list zihpm_config = { + .sublists = { + BASE_SUBLIST, + ZIHPM_REGS_SUBLIST, + {0}, + }, +}; + +static struct vcpu_reg_list aia_config = { + .sublists = { + BASE_SUBLIST, + AIA_REGS_SUBLIST, + {0}, + }, +}; + +static struct vcpu_reg_list fp_f_config = { + .sublists = { + BASE_SUBLIST, + FP_F_REGS_SUBLIST, + {0}, + }, +}; + +static struct vcpu_reg_list fp_d_config = { + .sublists = { + BASE_SUBLIST, + FP_D_REGS_SUBLIST, + {0}, + }, +}; + +struct vcpu_reg_list *vcpu_configs[] = { + &h_config, + &zicbom_config, + &zicboz_config, + &svpbmt_config, + &sstc_config, + &svinval_config, + &zihintpause_config, + &zba_config, + &zbb_config, + &zbs_config, + &zicntr_config, + &zicsr_config, + &zifencei_config, + &zihpm_config, + &aia_config, + &fp_f_config, + &fp_d_config, +}; +int vcpu_configs_n = ARRAY_SIZE(vcpu_configs); -- GitLab From e4c2450ae063415f2a504faa6d666b2d338b753e Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 22 Jun 2023 11:27:37 +0200 Subject: [PATCH 0969/3445] dt-bindings: iommu: qcom,iommu: Add qcom,ctx-asid property Add a new "qcom,ctx-asid" property to force an ASID number on IOMMU contexts where required. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230622092742.74819-2-angelogioacchino.delregno@collabora.com Signed-off-by: Will Deacon --- Documentation/devicetree/bindings/iommu/qcom,iommu.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/iommu/qcom,iommu.yaml b/Documentation/devicetree/bindings/iommu/qcom,iommu.yaml index d9fabdf930d98..f7a64ad8a0057 100644 --- a/Documentation/devicetree/bindings/iommu/qcom,iommu.yaml +++ b/Documentation/devicetree/bindings/iommu/qcom,iommu.yaml @@ -71,6 +71,11 @@ patternProperties: reg: maxItems: 1 + qcom,ctx-asid: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + The ASID number associated to the context bank. + required: - compatible - interrupts -- GitLab From a7a7c8c1a06a47ad87d9b10cec6a7cde4a041b23 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 22 Jun 2023 11:27:41 +0200 Subject: [PATCH 0970/3445] dt-bindings: iommu: qcom,iommu: Add QSMMUv2 and MSM8976 compatibles Add compatible string "qcom,msm-iommu-v2" for the inner node, along with "qcom,msm8976-iommu" as a first user of it and "qcom,msm-iommu-v2-ns" and "qcom,msm-iommu-v2-sec" for the context bank nodes to support Qualcomm's secure fw "SMMU v2" implementation. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230622092742.74819-6-angelogioacchino.delregno@collabora.com Signed-off-by: Will Deacon --- .../devicetree/bindings/iommu/qcom,iommu.yaml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/iommu/qcom,iommu.yaml b/Documentation/devicetree/bindings/iommu/qcom,iommu.yaml index f7a64ad8a0057..a74eb899c381e 100644 --- a/Documentation/devicetree/bindings/iommu/qcom,iommu.yaml +++ b/Documentation/devicetree/bindings/iommu/qcom,iommu.yaml @@ -17,11 +17,16 @@ description: | properties: compatible: - items: - - enum: - - qcom,msm8916-iommu - - qcom,msm8953-iommu - - const: qcom,msm-iommu-v1 + oneOf: + - items: + - enum: + - qcom,msm8916-iommu + - qcom,msm8953-iommu + - const: qcom,msm-iommu-v1 + - items: + - enum: + - qcom,msm8976-iommu + - const: qcom,msm-iommu-v2 clocks: items: @@ -64,6 +69,8 @@ patternProperties: enum: - qcom,msm-iommu-v1-ns - qcom,msm-iommu-v1-sec + - qcom,msm-iommu-v2-ns + - qcom,msm-iommu-v2-sec interrupts: maxItems: 1 -- GitLab From fcf226f1f7083cba76af47bf8dd764b68b149cd2 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 22 Jun 2023 11:27:38 +0200 Subject: [PATCH 0971/3445] iommu/qcom: Use the asid read from device-tree if specified As specified in this driver, the context banks are 0x1000 apart but on some SoCs the context number does not necessarily match this logic, hence we end up using the wrong ASID: keeping in mind that this IOMMU implementation relies heavily on SCM (TZ) calls, it is mandatory that we communicate the right context number. Since this is all about how context banks are mapped in firmware, which may be board dependent (as a different firmware version may eventually change the expected context bank numbers), introduce a new property "qcom,ctx-asid": when found, the ASID will be forced as read from the devicetree. When "qcom,ctx-asid" is not found, this driver retains the previous behavior as to avoid breaking older devicetrees or systems that do not require forcing ASID numbers. Signed-off-by: Marijn Suijten [Marijn: Rebased over next-20221111] Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230622092742.74819-3-angelogioacchino.delregno@collabora.com Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu/qcom_iommu.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c index abf798104830e..8c717bc2d9fbf 100644 --- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c +++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c @@ -531,7 +531,8 @@ static int qcom_iommu_of_xlate(struct device *dev, struct of_phandle_args *args) * index into qcom_iommu->ctxs: */ if (WARN_ON(asid < 1) || - WARN_ON(asid > qcom_iommu->num_ctxs)) { + WARN_ON(asid > qcom_iommu->num_ctxs) || + WARN_ON(qcom_iommu->ctxs[asid - 1] == NULL)) { put_device(&iommu_pdev->dev); return -EINVAL; } @@ -617,7 +618,8 @@ free_mem: static int get_asid(const struct device_node *np) { - u32 reg; + u32 reg, val; + int asid; /* read the "reg" property directly to get the relative address * of the context bank, and calculate the asid from that: @@ -625,7 +627,17 @@ static int get_asid(const struct device_node *np) if (of_property_read_u32_index(np, "reg", 0, ®)) return -ENODEV; - return reg / 0x1000; /* context banks are 0x1000 apart */ + /* + * Context banks are 0x1000 apart but, in some cases, the ASID + * number doesn't match to this logic and needs to be passed + * from the DT configuration explicitly. + */ + if (!of_property_read_u32(np, "qcom,ctx-asid", &val)) + asid = val; + else + asid = reg / 0x1000; + + return asid; } static int qcom_iommu_ctx_probe(struct platform_device *pdev) -- GitLab From 9f3fef23d9b5a858a6e6d5f478bb1b6b76265e76 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 22 Jun 2023 11:27:39 +0200 Subject: [PATCH 0972/3445] iommu/qcom: Disable and reset context bank before programming Writing the new TTBRs, TCRs and MAIRs on a previously enabled context bank may trigger a context fault, resulting in firmware driven AP resets: change the domain initialization programming sequence to disable the context bank(s) and to also clear the related fault address (CB_FAR) and fault status (CB_FSR) registers before writing new values to TTBR0/1, TCR/TCR2, MAIR0/1. Fixes: 0ae349a0f33f ("iommu/qcom: Add qcom_iommu") Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230622092742.74819-4-angelogioacchino.delregno@collabora.com Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu/qcom_iommu.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c index 8c717bc2d9fbf..a352859edea8b 100644 --- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c +++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c @@ -273,6 +273,13 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain, ctx->secure_init = true; } + /* Disable context bank before programming */ + iommu_writel(ctx, ARM_SMMU_CB_SCTLR, 0); + + /* Clear context bank fault address fault status registers */ + iommu_writel(ctx, ARM_SMMU_CB_FAR, 0); + iommu_writel(ctx, ARM_SMMU_CB_FSR, ARM_SMMU_FSR_FAULT); + /* TTBRs */ iommu_writeq(ctx, ARM_SMMU_CB_TTBR0, pgtbl_cfg.arm_lpae_s1_cfg.ttbr | -- GitLab From ec5601661bfcdc206e6ceba1b97837e763dab1ba Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 22 Jun 2023 11:27:40 +0200 Subject: [PATCH 0973/3445] iommu/qcom: Index contexts by asid number to allow asid 0 This driver was indexing the contexts by asid-1, which is probably done under the assumption that the first ASID is always 1. Unfortunately this is not always true: at least for MSM8956 and MSM8976's GPU IOMMU, the gpu_user context's ASID number is zero. To allow using a zero asid number, index the contexts by `asid` instead of by `asid - 1`. While at it, also enhance human readability by renaming the `num_ctxs` member of struct qcom_iommu_dev to `max_asid`. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230622092742.74819-5-angelogioacchino.delregno@collabora.com Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu/qcom_iommu.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c index a352859edea8b..60e4959cc9fdd 100644 --- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c +++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c @@ -51,8 +51,8 @@ struct qcom_iommu_dev { struct clk_bulk_data clks[CLK_NUM]; void __iomem *local_base; u32 sec_id; - u8 num_ctxs; - struct qcom_iommu_ctx *ctxs[]; /* indexed by asid-1 */ + u8 max_asid; + struct qcom_iommu_ctx *ctxs[]; /* indexed by asid */ }; struct qcom_iommu_ctx { @@ -94,7 +94,7 @@ static struct qcom_iommu_ctx * to_ctx(struct qcom_iommu_domain *d, unsigned asid struct qcom_iommu_dev *qcom_iommu = d->iommu; if (!qcom_iommu) return NULL; - return qcom_iommu->ctxs[asid - 1]; + return qcom_iommu->ctxs[asid]; } static inline void @@ -534,12 +534,10 @@ static int qcom_iommu_of_xlate(struct device *dev, struct of_phandle_args *args) qcom_iommu = platform_get_drvdata(iommu_pdev); /* make sure the asid specified in dt is valid, so we don't have - * to sanity check this elsewhere, since 'asid - 1' is used to - * index into qcom_iommu->ctxs: + * to sanity check this elsewhere: */ - if (WARN_ON(asid < 1) || - WARN_ON(asid > qcom_iommu->num_ctxs) || - WARN_ON(qcom_iommu->ctxs[asid - 1] == NULL)) { + if (WARN_ON(asid > qcom_iommu->max_asid) || + WARN_ON(qcom_iommu->ctxs[asid] == NULL)) { put_device(&iommu_pdev->dev); return -EINVAL; } @@ -694,7 +692,7 @@ static int qcom_iommu_ctx_probe(struct platform_device *pdev) dev_dbg(dev, "found asid %u\n", ctx->asid); - qcom_iommu->ctxs[ctx->asid - 1] = ctx; + qcom_iommu->ctxs[ctx->asid] = ctx; return 0; } @@ -706,7 +704,7 @@ static void qcom_iommu_ctx_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); - qcom_iommu->ctxs[ctx->asid - 1] = NULL; + qcom_iommu->ctxs[ctx->asid] = NULL; } static const struct of_device_id ctx_of_match[] = { @@ -753,11 +751,11 @@ static int qcom_iommu_device_probe(struct platform_device *pdev) for_each_child_of_node(dev->of_node, child) max_asid = max(max_asid, get_asid(child)); - qcom_iommu = devm_kzalloc(dev, struct_size(qcom_iommu, ctxs, max_asid), + qcom_iommu = devm_kzalloc(dev, struct_size(qcom_iommu, ctxs, max_asid + 1), GFP_KERNEL); if (!qcom_iommu) return -ENOMEM; - qcom_iommu->num_ctxs = max_asid; + qcom_iommu->max_asid = max_asid; qcom_iommu->dev = dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- GitLab From e30c960d3f44b7aaa0861ce4afa8ba8b8f4b0f03 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 22 Jun 2023 11:27:42 +0200 Subject: [PATCH 0974/3445] iommu/qcom: Add support for QSMMUv2 and QSMMU-500 secured contexts On some SoCs like MSM8956, MSM8976 and others, secure contexts are also secured: these get programmed by the bootloader or TZ (as usual) but their "interesting" registers are locked out by the hypervisor, disallowing direct register writes from Linux and, in many cases, completely disallowing the reprogramming of TTBR, TCR, MAIR and other registers including, but not limited to, resetting contexts. This is referred downstream as a "v2" IOMMU but this is effectively a "v2 firmware configuration" instead. Luckily, the described behavior of version 2 is effective only on secure contexts and not on non-secure ones: add support for that, finally getting a completely working IOMMU on at least MSM8956/76. Signed-off-by: Marijn Suijten [Marijn: Rebased over next-20221111] Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230622092742.74819-7-angelogioacchino.delregno@collabora.com Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu/qcom_iommu.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c index 60e4959cc9fdd..3f788912b6399 100644 --- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c +++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c @@ -59,6 +59,7 @@ struct qcom_iommu_ctx { struct device *dev; void __iomem *base; bool secure_init; + bool secured_ctx; u8 asid; /* asid and ctx bank # are 1:1 */ struct iommu_domain *domain; }; @@ -273,6 +274,12 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain, ctx->secure_init = true; } + /* Secured QSMMU-500/QSMMU-v2 contexts cannot be programmed */ + if (ctx->secured_ctx) { + ctx->domain = domain; + continue; + } + /* Disable context bank before programming */ iommu_writel(ctx, ARM_SMMU_CB_SCTLR, 0); @@ -667,10 +674,14 @@ static int qcom_iommu_ctx_probe(struct platform_device *pdev) if (irq < 0) return irq; + if (of_device_is_compatible(dev->of_node, "qcom,msm-iommu-v2-sec")) + ctx->secured_ctx = true; + /* clear IRQs before registering fault handler, just in case the * boot-loader left us a surprise: */ - iommu_writel(ctx, ARM_SMMU_CB_FSR, iommu_readl(ctx, ARM_SMMU_CB_FSR)); + if (!ctx->secured_ctx) + iommu_writel(ctx, ARM_SMMU_CB_FSR, iommu_readl(ctx, ARM_SMMU_CB_FSR)); ret = devm_request_irq(dev, irq, qcom_iommu_fault, @@ -710,6 +721,8 @@ static void qcom_iommu_ctx_remove(struct platform_device *pdev) static const struct of_device_id ctx_of_match[] = { { .compatible = "qcom,msm-iommu-v1-ns" }, { .compatible = "qcom,msm-iommu-v1-sec" }, + { .compatible = "qcom,msm-iommu-v2-ns" }, + { .compatible = "qcom,msm-iommu-v2-sec" }, { /* sentinel */ } }; @@ -727,7 +740,8 @@ static bool qcom_iommu_has_secure_context(struct qcom_iommu_dev *qcom_iommu) struct device_node *child; for_each_child_of_node(qcom_iommu->dev->of_node, child) { - if (of_device_is_compatible(child, "qcom,msm-iommu-v1-sec")) { + if (of_device_is_compatible(child, "qcom,msm-iommu-v1-sec") || + of_device_is_compatible(child, "qcom,msm-iommu-v2-sec")) { of_node_put(child); return true; } @@ -871,6 +885,7 @@ static const struct dev_pm_ops qcom_iommu_pm_ops = { static const struct of_device_id qcom_iommu_of_match[] = { { .compatible = "qcom,msm-iommu-v1" }, + { .compatible = "qcom,msm-iommu-v2" }, { /* sentinel */ } }; -- GitLab From 4298780126c298f20ae4bc8676591eaf8c48767e Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Wed, 9 Aug 2023 20:47:54 +0800 Subject: [PATCH 0975/3445] iommu: Generalize PASID 0 for normal DMA w/o PASID PCIe Process address space ID (PASID) is used to tag DMA traffic, it provides finer grained isolation than requester ID (RID). For each device/RID, 0 is a special PASID for the normal DMA (no PASID). This is universal across all architectures that supports PASID, therefore warranted to be reserved globally and declared in the common header. Consequently, we can avoid the conflict between different PASID use cases in the generic code. e.g. SVA and DMA API with PASIDs. This paved away for device drivers to choose global PASID policy while continue doing normal DMA. Noting that VT-d could support none-zero RID/NO_PASID, but currently not used. Reviewed-by: Lu Baolu Reviewed-by: Kevin Tian Reviewed-by: Jean-Philippe Brucker Reviewed-by: Jason Gunthorpe Signed-off-by: Jacob Pan Link: https://lore.kernel.org/r/20230802212427.1497170-2-jacob.jun.pan@linux.intel.com Signed-off-by: Lu Baolu Signed-off-by: Joerg Roedel --- .../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 2 +- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 16 ++++++------- drivers/iommu/intel/iommu.c | 24 +++++++++---------- drivers/iommu/intel/pasid.c | 2 +- drivers/iommu/intel/pasid.h | 2 -- include/linux/iommu.h | 1 + 6 files changed, 23 insertions(+), 24 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c index a5a63b1c947eb..5e6b39881c042 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c @@ -80,7 +80,7 @@ arm_smmu_share_asid(struct mm_struct *mm, u16 asid) * be some overlap between use of both ASIDs, until we invalidate the * TLB. */ - arm_smmu_write_ctx_desc(smmu_domain, 0, cd); + arm_smmu_write_ctx_desc(smmu_domain, IOMMU_NO_PASID, cd); /* Invalidate TLB entries previously associated with that context */ arm_smmu_tlb_inv_asid(smmu, asid); diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index 9b0dc35056019..ee70687f060b2 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -1059,7 +1059,7 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, int ssid, /* * This function handles the following cases: * - * (1) Install primary CD, for normal DMA traffic (SSID = 0). + * (1) Install primary CD, for normal DMA traffic (SSID = IOMMU_NO_PASID = 0). * (2) Install a secondary CD, for SID+SSID traffic. * (3) Update ASID of a CD. Atomically write the first 64 bits of the * CD, then invalidate the old entry and mappings. @@ -1607,7 +1607,7 @@ static void arm_smmu_handle_ppr(struct arm_smmu_device *smmu, u64 *evt) sid = FIELD_GET(PRIQ_0_SID, evt[0]); ssv = FIELD_GET(PRIQ_0_SSID_V, evt[0]); - ssid = ssv ? FIELD_GET(PRIQ_0_SSID, evt[0]) : 0; + ssid = ssv ? FIELD_GET(PRIQ_0_SSID, evt[0]) : IOMMU_NO_PASID; last = FIELD_GET(PRIQ_0_PRG_LAST, evt[0]); grpid = FIELD_GET(PRIQ_1_PRG_IDX, evt[1]); @@ -1748,7 +1748,7 @@ arm_smmu_atc_inv_to_cmd(int ssid, unsigned long iova, size_t size, */ *cmd = (struct arm_smmu_cmdq_ent) { .opcode = CMDQ_OP_ATC_INV, - .substream_valid = !!ssid, + .substream_valid = (ssid != IOMMU_NO_PASID), .atc.ssid = ssid, }; @@ -1795,7 +1795,7 @@ static int arm_smmu_atc_inv_master(struct arm_smmu_master *master) struct arm_smmu_cmdq_ent cmd; struct arm_smmu_cmdq_batch cmds; - arm_smmu_atc_inv_to_cmd(0, 0, 0, &cmd); + arm_smmu_atc_inv_to_cmd(IOMMU_NO_PASID, 0, 0, &cmd); cmds.num = 0; for (i = 0; i < master->num_streams; i++) { @@ -1875,7 +1875,7 @@ static void arm_smmu_tlb_inv_context(void *cookie) cmd.tlbi.vmid = smmu_domain->s2_cfg.vmid; arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd); } - arm_smmu_atc_inv_domain(smmu_domain, 0, 0, 0); + arm_smmu_atc_inv_domain(smmu_domain, IOMMU_NO_PASID, 0, 0); } static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd, @@ -1968,7 +1968,7 @@ static void arm_smmu_tlb_inv_range_domain(unsigned long iova, size_t size, * Unfortunately, this can't be leaf-only since we may have * zapped an entire table. */ - arm_smmu_atc_inv_domain(smmu_domain, 0, iova, size); + arm_smmu_atc_inv_domain(smmu_domain, IOMMU_NO_PASID, iova, size); } void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid, @@ -2142,7 +2142,7 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain, * the master has been added to the devices list for this domain. * This isn't an issue because the STE hasn't been installed yet. */ - ret = arm_smmu_write_ctx_desc(smmu_domain, 0, &cfg->cd); + ret = arm_smmu_write_ctx_desc(smmu_domain, IOMMU_NO_PASID, &cfg->cd); if (ret) goto out_free_cd_tables; @@ -2328,7 +2328,7 @@ static void arm_smmu_enable_ats(struct arm_smmu_master *master) pdev = to_pci_dev(master->dev); atomic_inc(&smmu_domain->nr_ats_masters); - arm_smmu_atc_inv_domain(smmu_domain, 0, 0, 0); + arm_smmu_atc_inv_domain(smmu_domain, IOMMU_NO_PASID, 0, 0); if (pci_enable_ats(pdev, stu)) dev_err(master->dev, "Failed to enable ATS (STU %zu)\n", stu); } diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index 5c8c5cdc36cf5..ddff43def3ab2 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -877,7 +877,7 @@ void dmar_fault_dump_ptes(struct intel_iommu *iommu, u16 source_id, } /* For request-without-pasid, get the pasid from context entry */ if (intel_iommu_sm && pasid == IOMMU_PASID_INVALID) - pasid = PASID_RID2PASID; + pasid = IOMMU_NO_PASID; dir_index = pasid >> PASID_PDE_SHIFT; pde = &dir[dir_index]; @@ -1449,7 +1449,7 @@ static void __iommu_flush_dev_iotlb(struct device_domain_info *info, qdep = info->ats_qdep; qi_flush_dev_iotlb(info->iommu, sid, info->pfsid, qdep, addr, mask); - quirk_extra_dev_tlb_flush(info, addr, mask, PASID_RID2PASID, qdep); + quirk_extra_dev_tlb_flush(info, addr, mask, IOMMU_NO_PASID, qdep); } static void iommu_flush_dev_iotlb(struct dmar_domain *domain, @@ -1484,7 +1484,7 @@ static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, ih = 1 << 6; if (domain->use_first_level) { - qi_flush_piotlb(iommu, did, PASID_RID2PASID, addr, pages, ih); + qi_flush_piotlb(iommu, did, IOMMU_NO_PASID, addr, pages, ih); } else { unsigned long bitmask = aligned_pages - 1; @@ -1554,7 +1554,7 @@ static void intel_flush_iotlb_all(struct iommu_domain *domain) u16 did = domain_id_iommu(dmar_domain, iommu); if (dmar_domain->use_first_level) - qi_flush_piotlb(iommu, did, PASID_RID2PASID, 0, -1, 0); + qi_flush_piotlb(iommu, did, IOMMU_NO_PASID, 0, -1, 0); else iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH); @@ -1940,7 +1940,7 @@ static int domain_context_mapping_one(struct dmar_domain *domain, context_pdts(pds); /* Setup the RID_PASID field: */ - context_set_sm_rid2pasid(context, PASID_RID2PASID); + context_set_sm_rid2pasid(context, IOMMU_NO_PASID); /* * Setup the Device-TLB enable bit and Page request @@ -2420,13 +2420,13 @@ static int dmar_domain_attach_device(struct dmar_domain *domain, /* Setup the PASID entry for requests without PASID: */ if (hw_pass_through && domain_type_is_si(domain)) ret = intel_pasid_setup_pass_through(iommu, domain, - dev, PASID_RID2PASID); + dev, IOMMU_NO_PASID); else if (domain->use_first_level) ret = domain_setup_first_level(iommu, domain, dev, - PASID_RID2PASID); + IOMMU_NO_PASID); else ret = intel_pasid_setup_second_level(iommu, domain, - dev, PASID_RID2PASID); + dev, IOMMU_NO_PASID); if (ret) { dev_err(dev, "Setup RID2PASID failed\n"); device_block_translation(dev); @@ -3968,7 +3968,7 @@ static void dmar_remove_one_dev_info(struct device *dev) if (!dev_is_real_dma_subdevice(info->dev)) { if (dev_is_pci(info->dev) && sm_supported(iommu)) intel_pasid_tear_down_entry(iommu, info->dev, - PASID_RID2PASID, false); + IOMMU_NO_PASID, false); iommu_disable_pci_caps(info); domain_context_clear(info); @@ -3997,7 +3997,7 @@ static void device_block_translation(struct device *dev) if (!dev_is_real_dma_subdevice(dev)) { if (sm_supported(iommu)) intel_pasid_tear_down_entry(iommu, dev, - PASID_RID2PASID, false); + IOMMU_NO_PASID, false); else domain_context_clear(info); } @@ -4331,7 +4331,7 @@ static void domain_set_force_snooping(struct dmar_domain *domain) list_for_each_entry(info, &domain->devices, link) intel_pasid_setup_page_snoop_control(info->iommu, info->dev, - PASID_RID2PASID); + IOMMU_NO_PASID); } static bool intel_iommu_enforce_cache_coherency(struct iommu_domain *domain) @@ -4987,7 +4987,7 @@ void quirk_extra_dev_tlb_flush(struct device_domain_info *info, return; sid = PCI_DEVID(info->bus, info->devfn); - if (pasid == PASID_RID2PASID) { + if (pasid == IOMMU_NO_PASID) { qi_flush_dev_iotlb(info->iommu, sid, info->pfsid, qdep, address, mask); } else { diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c index c5d479770e12e..23dca3bc319d8 100644 --- a/drivers/iommu/intel/pasid.c +++ b/drivers/iommu/intel/pasid.c @@ -438,7 +438,7 @@ devtlb_invalidation_with_pasid(struct intel_iommu *iommu, * SVA usage, device could do DMA with multiple PASIDs. It is more * efficient to flush devTLB specific to the PASID. */ - if (pasid == PASID_RID2PASID) + if (pasid == IOMMU_NO_PASID) qi_flush_dev_iotlb(iommu, sid, pfsid, qdep, 0, 64 - VTD_PAGE_SHIFT); else qi_flush_dev_iotlb_pasid(iommu, sid, pfsid, pasid, qdep, 0, 64 - VTD_PAGE_SHIFT); diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h index d6b7d21244b11..4e9e68c3c3888 100644 --- a/drivers/iommu/intel/pasid.h +++ b/drivers/iommu/intel/pasid.h @@ -10,8 +10,6 @@ #ifndef __INTEL_PASID_H #define __INTEL_PASID_H -#define PASID_RID2PASID 0x0 -#define PASID_MIN 0x1 #define PASID_MAX 0x100000 #define PASID_PTE_MASK 0x3F #define PASID_PTE_PRESENT 1 diff --git a/include/linux/iommu.h b/include/linux/iommu.h index d316425966759..2870bc29d456a 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -196,6 +196,7 @@ enum iommu_dev_features { IOMMU_DEV_FEAT_IOPF, }; +#define IOMMU_NO_PASID (0U) /* Reserved for DMA w/o PASID */ #define IOMMU_PASID_INVALID (-1U) typedef unsigned int ioasid_t; -- GitLab From 2dcebc7ddce7ffd4015824227c7623558b89d721 Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Wed, 9 Aug 2023 20:47:55 +0800 Subject: [PATCH 0976/3445] iommu: Move global PASID allocation from SVA to core Intel ENQCMD requires a single PASID to be shared between multiple devices, as the PASID is stored in a single MSR register per-process and userspace can use only that one PASID. This means that the PASID allocation for any ENQCMD using device driver must always come from a shared global pool, regardless of what kind of domain the PASID will be used with. Split the code for the global PASID allocator into iommu_alloc/free_global_pasid() so that drivers can attach non-SVA domains to PASIDs as well. This patch moves global PASID allocation APIs from SVA to IOMMU APIs. Reserved PASIDs, currently only RID_PASID, are excluded from the global PASID allocation. It is expected that device drivers will use the allocated PASIDs to attach to appropriate IOMMU domains for use. Reviewed-by: Lu Baolu Reviewed-by: Kevin Tian Reviewed-by: Jason Gunthorpe Signed-off-by: Jacob Pan Link: https://lore.kernel.org/r/20230802212427.1497170-3-jacob.jun.pan@linux.intel.com Signed-off-by: Lu Baolu Signed-off-by: Joerg Roedel --- drivers/iommu/iommu-sva.c | 29 ++++++++++------------------- drivers/iommu/iommu.c | 28 ++++++++++++++++++++++++++++ include/linux/iommu.h | 10 ++++++++++ 3 files changed, 48 insertions(+), 19 deletions(-) diff --git a/drivers/iommu/iommu-sva.c b/drivers/iommu/iommu-sva.c index 05c0fb2acbc44..b78671a8a9143 100644 --- a/drivers/iommu/iommu-sva.c +++ b/drivers/iommu/iommu-sva.c @@ -10,34 +10,30 @@ #include "iommu-sva.h" static DEFINE_MUTEX(iommu_sva_lock); -static DEFINE_IDA(iommu_global_pasid_ida); /* Allocate a PASID for the mm within range (inclusive) */ -static int iommu_sva_alloc_pasid(struct mm_struct *mm, ioasid_t min, ioasid_t max) +static int iommu_sva_alloc_pasid(struct mm_struct *mm, struct device *dev) { + ioasid_t pasid; int ret = 0; - if (min == IOMMU_PASID_INVALID || - max == IOMMU_PASID_INVALID || - min == 0 || max < min) - return -EINVAL; - if (!arch_pgtable_dma_compat(mm)) return -EBUSY; mutex_lock(&iommu_sva_lock); /* Is a PASID already associated with this mm? */ if (mm_valid_pasid(mm)) { - if (mm->pasid < min || mm->pasid > max) + if (mm->pasid >= dev->iommu->max_pasids) ret = -EOVERFLOW; goto out; } - ret = ida_alloc_range(&iommu_global_pasid_ida, min, max, GFP_KERNEL); - if (ret < 0) + pasid = iommu_alloc_global_pasid(dev); + if (pasid == IOMMU_PASID_INVALID) { + ret = -ENOSPC; goto out; - - mm->pasid = ret; + } + mm->pasid = pasid; ret = 0; out: mutex_unlock(&iommu_sva_lock); @@ -64,15 +60,10 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm { struct iommu_domain *domain; struct iommu_sva *handle; - ioasid_t max_pasids; int ret; - max_pasids = dev->iommu->max_pasids; - if (!max_pasids) - return ERR_PTR(-EOPNOTSUPP); - /* Allocate mm->pasid if necessary. */ - ret = iommu_sva_alloc_pasid(mm, 1, max_pasids - 1); + ret = iommu_sva_alloc_pasid(mm, dev); if (ret) return ERR_PTR(ret); @@ -217,5 +208,5 @@ void mm_pasid_drop(struct mm_struct *mm) if (likely(!mm_valid_pasid(mm))) return; - ida_free(&iommu_global_pasid_ida, mm->pasid); + iommu_free_global_pasid(mm->pasid); } diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index caaf563d38ae0..d199d144460c1 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -39,6 +39,7 @@ static struct kset *iommu_group_kset; static DEFINE_IDA(iommu_group_ida); +static DEFINE_IDA(iommu_global_pasid_ida); static unsigned int iommu_def_domain_type __read_mostly; static bool iommu_dma_strict __read_mostly = IS_ENABLED(CONFIG_IOMMU_DEFAULT_DMA_STRICT); @@ -3400,3 +3401,30 @@ struct iommu_domain *iommu_sva_domain_alloc(struct device *dev, return domain; } + +ioasid_t iommu_alloc_global_pasid(struct device *dev) +{ + int ret; + + /* max_pasids == 0 means that the device does not support PASID */ + if (!dev->iommu->max_pasids) + return IOMMU_PASID_INVALID; + + /* + * max_pasids is set up by vendor driver based on number of PASID bits + * supported but the IDA allocation is inclusive. + */ + ret = ida_alloc_range(&iommu_global_pasid_ida, IOMMU_FIRST_GLOBAL_PASID, + dev->iommu->max_pasids - 1, GFP_KERNEL); + return ret < 0 ? IOMMU_PASID_INVALID : ret; +} +EXPORT_SYMBOL_GPL(iommu_alloc_global_pasid); + +void iommu_free_global_pasid(ioasid_t pasid) +{ + if (WARN_ON(pasid == IOMMU_PASID_INVALID)) + return; + + ida_free(&iommu_global_pasid_ida, pasid); +} +EXPORT_SYMBOL_GPL(iommu_free_global_pasid); diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 2870bc29d456a..6b821cb715d5a 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -197,6 +197,7 @@ enum iommu_dev_features { }; #define IOMMU_NO_PASID (0U) /* Reserved for DMA w/o PASID */ +#define IOMMU_FIRST_GLOBAL_PASID (1U) /*starting range for allocation */ #define IOMMU_PASID_INVALID (-1U) typedef unsigned int ioasid_t; @@ -728,6 +729,8 @@ void iommu_detach_device_pasid(struct iommu_domain *domain, struct iommu_domain * iommu_get_domain_for_dev_pasid(struct device *dev, ioasid_t pasid, unsigned int type); +ioasid_t iommu_alloc_global_pasid(struct device *dev); +void iommu_free_global_pasid(ioasid_t pasid); #else /* CONFIG_IOMMU_API */ struct iommu_ops {}; @@ -1089,6 +1092,13 @@ iommu_get_domain_for_dev_pasid(struct device *dev, ioasid_t pasid, { return NULL; } + +static inline ioasid_t iommu_alloc_global_pasid(struct device *dev) +{ + return IOMMU_PASID_INVALID; +} + +static inline void iommu_free_global_pasid(ioasid_t pasid) {} #endif /* CONFIG_IOMMU_API */ /** -- GitLab From ac1a3483febd0ec8fced1ccb15da349dcc360fbb Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Wed, 9 Aug 2023 20:47:56 +0800 Subject: [PATCH 0977/3445] iommu/vt-d: Add domain_flush_pasid_iotlb() The VT-d spec requires to use PASID-based-IOTLB invalidation descriptor to invalidate IOTLB and the paging-structure caches for a first-stage page table. Add a generic helper to do this. RID2PASID is used if the domain has been attached to a physical device, otherwise real PASIDs that the domain has been attached to will be used. The 'real' PASID attachment is handled in the subsequent change. Signed-off-by: Lu Baolu Signed-off-by: Jacob Pan Reviewed-by: Kevin Tian Link: https://lore.kernel.org/r/20230802212427.1497170-4-jacob.jun.pan@linux.intel.com Signed-off-by: Joerg Roedel --- drivers/iommu/intel/iommu.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index ddff43def3ab2..ecb7e44377a84 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -1467,6 +1467,18 @@ static void iommu_flush_dev_iotlb(struct dmar_domain *domain, spin_unlock_irqrestore(&domain->lock, flags); } +static void domain_flush_pasid_iotlb(struct intel_iommu *iommu, + struct dmar_domain *domain, u64 addr, + unsigned long npages, bool ih) +{ + u16 did = domain_id_iommu(domain, iommu); + unsigned long flags; + + spin_lock_irqsave(&domain->lock, flags); + qi_flush_piotlb(iommu, did, IOMMU_NO_PASID, addr, npages, ih); + spin_unlock_irqrestore(&domain->lock, flags); +} + static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, struct dmar_domain *domain, unsigned long pfn, unsigned int pages, @@ -1484,7 +1496,7 @@ static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, ih = 1 << 6; if (domain->use_first_level) { - qi_flush_piotlb(iommu, did, IOMMU_NO_PASID, addr, pages, ih); + domain_flush_pasid_iotlb(iommu, domain, addr, pages, ih); } else { unsigned long bitmask = aligned_pages - 1; @@ -1554,7 +1566,7 @@ static void intel_flush_iotlb_all(struct iommu_domain *domain) u16 did = domain_id_iommu(dmar_domain, iommu); if (dmar_domain->use_first_level) - qi_flush_piotlb(iommu, did, IOMMU_NO_PASID, 0, -1, 0); + domain_flush_pasid_iotlb(iommu, dmar_domain, 0, -1, 0); else iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH); -- GitLab From b61701881f2ff809e9cd229f129bdc4e09ca688e Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Wed, 9 Aug 2023 20:47:57 +0800 Subject: [PATCH 0978/3445] iommu/vt-d: Remove pasid_mutex The pasid_mutex was used to protect the paths of set/remove_dev_pasid(). It's duplicate with iommu_sva_lock. Remove it to avoid duplicate code. Signed-off-by: Lu Baolu Signed-off-by: Jacob Pan Reviewed-by: Kevin Tian Link: https://lore.kernel.org/r/20230802212427.1497170-5-jacob.jun.pan@linux.intel.com Signed-off-by: Joerg Roedel --- drivers/iommu/intel/svm.c | 45 +++++---------------------------------- 1 file changed, 5 insertions(+), 40 deletions(-) diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c index e95b339e9cdc0..2a82864e9d578 100644 --- a/drivers/iommu/intel/svm.c +++ b/drivers/iommu/intel/svm.c @@ -259,8 +259,6 @@ static const struct mmu_notifier_ops intel_mmuops = { .invalidate_range = intel_invalidate_range, }; -static DEFINE_MUTEX(pasid_mutex); - static int pasid_to_svm_sdev(struct device *dev, unsigned int pasid, struct intel_svm **rsvm, struct intel_svm_dev **rsdev) @@ -268,10 +266,6 @@ static int pasid_to_svm_sdev(struct device *dev, unsigned int pasid, struct intel_svm_dev *sdev = NULL; struct intel_svm *svm; - /* The caller should hold the pasid_mutex lock */ - if (WARN_ON(!mutex_is_locked(&pasid_mutex))) - return -EINVAL; - if (pasid == IOMMU_PASID_INVALID || pasid >= PASID_MAX) return -EINVAL; @@ -371,22 +365,19 @@ free_svm: return ret; } -/* Caller must hold pasid_mutex */ -static int intel_svm_unbind_mm(struct device *dev, u32 pasid) +void intel_svm_remove_dev_pasid(struct device *dev, u32 pasid) { struct intel_svm_dev *sdev; struct intel_iommu *iommu; struct intel_svm *svm; struct mm_struct *mm; - int ret = -EINVAL; iommu = device_to_iommu(dev, NULL, NULL); if (!iommu) - goto out; + return; - ret = pasid_to_svm_sdev(dev, pasid, &svm, &sdev); - if (ret) - goto out; + if (pasid_to_svm_sdev(dev, pasid, &svm, &sdev)) + return; mm = svm->mm; if (sdev) { @@ -418,8 +409,6 @@ static int intel_svm_unbind_mm(struct device *dev, u32 pasid) kfree(svm); } } -out: - return ret; } /* Page request queue descriptor */ @@ -520,19 +509,7 @@ prq_retry: goto prq_retry; } - /* - * A work in IO page fault workqueue may try to lock pasid_mutex now. - * Holding pasid_mutex while waiting in iopf_queue_flush_dev() for - * all works in the workqueue to finish may cause deadlock. - * - * It's unnecessary to hold pasid_mutex in iopf_queue_flush_dev(). - * Unlock it to allow the works to be handled while waiting for - * them to finish. - */ - lockdep_assert_held(&pasid_mutex); - mutex_unlock(&pasid_mutex); iopf_queue_flush_dev(dev); - mutex_lock(&pasid_mutex); /* * Perform steps described in VT-d spec CH7.10 to drain page @@ -827,26 +804,14 @@ out: return ret; } -void intel_svm_remove_dev_pasid(struct device *dev, ioasid_t pasid) -{ - mutex_lock(&pasid_mutex); - intel_svm_unbind_mm(dev, pasid); - mutex_unlock(&pasid_mutex); -} - static int intel_svm_set_dev_pasid(struct iommu_domain *domain, struct device *dev, ioasid_t pasid) { struct device_domain_info *info = dev_iommu_priv_get(dev); struct intel_iommu *iommu = info->iommu; struct mm_struct *mm = domain->mm; - int ret; - mutex_lock(&pasid_mutex); - ret = intel_svm_bind_mm(iommu, dev, mm); - mutex_unlock(&pasid_mutex); - - return ret; + return intel_svm_bind_mm(iommu, dev, mm); } static void intel_svm_domain_free(struct iommu_domain *domain) -- GitLab From 154786235d0156ddce9575f13e23f3169e688435 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Wed, 9 Aug 2023 20:47:58 +0800 Subject: [PATCH 0979/3445] iommu/vt-d: Make prq draining code generic Currently draining page requests and responses for a pasid is part of SVA implementation. This is because the driver only supports attaching an SVA domain to a device pasid. As we are about to support attaching other types of domains to a device pasid, the prq draining code becomes generic. Signed-off-by: Lu Baolu Signed-off-by: Jacob Pan Reviewed-by: Kevin Tian Link: https://lore.kernel.org/r/20230802212427.1497170-6-jacob.jun.pan@linux.intel.com Signed-off-by: Joerg Roedel --- drivers/iommu/intel/iommu.c | 30 +++++++++++++++++++----------- drivers/iommu/intel/iommu.h | 2 ++ drivers/iommu/intel/svm.c | 17 ++--------------- 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index ecb7e44377a84..574021c36db56 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -4727,21 +4727,29 @@ static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid) struct intel_iommu *iommu = device_to_iommu(dev, NULL, NULL); struct iommu_domain *domain; - /* Domain type specific cleanup: */ domain = iommu_get_domain_for_dev_pasid(dev, pasid, 0); - if (domain) { - switch (domain->type) { - case IOMMU_DOMAIN_SVA: - intel_svm_remove_dev_pasid(dev, pasid); - break; - default: - /* should never reach here */ - WARN_ON(1); - break; - } + if (WARN_ON_ONCE(!domain)) + goto out_tear_down; + + /* + * The SVA implementation needs to handle its own stuffs like the mm + * notification. Before consolidating that code into iommu core, let + * the intel sva code handle it. + */ + if (domain->type == IOMMU_DOMAIN_SVA) { + intel_svm_remove_dev_pasid(dev, pasid); + goto out_tear_down; } + /* + * Should never reach here until we add support for attaching + * non-SVA domain to a pasid. + */ + WARN_ON(1); + +out_tear_down: intel_pasid_tear_down_entry(iommu, dev, pasid, false); + intel_drain_pasid_prq(dev, pasid); } const struct iommu_ops intel_iommu_ops = { diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h index 1c5e1d88862ba..6d94a29f5d52e 100644 --- a/drivers/iommu/intel/iommu.h +++ b/drivers/iommu/intel/iommu.h @@ -844,6 +844,7 @@ int intel_svm_page_response(struct device *dev, struct iommu_fault_event *evt, struct iommu_page_response *msg); struct iommu_domain *intel_svm_domain_alloc(void); void intel_svm_remove_dev_pasid(struct device *dev, ioasid_t pasid); +void intel_drain_pasid_prq(struct device *dev, u32 pasid); struct intel_svm_dev { struct list_head list; @@ -862,6 +863,7 @@ struct intel_svm { }; #else static inline void intel_svm_check(struct intel_iommu *iommu) {} +static inline void intel_drain_pasid_prq(struct device *dev, u32 pasid) {} static inline struct iommu_domain *intel_svm_domain_alloc(void) { return NULL; diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c index 2a82864e9d578..9fbae9af66159 100644 --- a/drivers/iommu/intel/svm.c +++ b/drivers/iommu/intel/svm.c @@ -26,8 +26,6 @@ #include "trace.h" static irqreturn_t prq_event_thread(int irq, void *d); -static void intel_svm_drain_prq(struct device *dev, u32 pasid); -#define to_intel_svm_dev(handle) container_of(handle, struct intel_svm_dev, sva) static DEFINE_XARRAY_ALLOC(pasid_private_array); static int pasid_private_add(ioasid_t pasid, void *priv) @@ -382,17 +380,6 @@ void intel_svm_remove_dev_pasid(struct device *dev, u32 pasid) if (sdev) { list_del_rcu(&sdev->list); - /* - * Flush the PASID cache and IOTLB for this device. - * Note that we do depend on the hardware *not* using - * the PASID any more. Just as we depend on other - * devices never using PASIDs that they have no right - * to use. We have a *shared* PASID table, because it's - * large and has to be physically contiguous. So it's - * hard to be as defensive as we might like. - */ - intel_pasid_tear_down_entry(iommu, dev, svm->pasid, false); - intel_svm_drain_prq(dev, svm->pasid); kfree_rcu(sdev, rcu); if (list_empty(&svm->devs)) { @@ -449,7 +436,7 @@ static bool is_canonical_address(u64 addr) } /** - * intel_svm_drain_prq - Drain page requests and responses for a pasid + * intel_drain_pasid_prq - Drain page requests and responses for a pasid * @dev: target device * @pasid: pasid for draining * @@ -463,7 +450,7 @@ static bool is_canonical_address(u64 addr) * described in VT-d spec CH7.10 to drain all page requests and page * responses pending in the hardware. */ -static void intel_svm_drain_prq(struct device *dev, u32 pasid) +void intel_drain_pasid_prq(struct device *dev, u32 pasid) { struct device_domain_info *info; struct dmar_domain *domain; -- GitLab From 37f900e7180ac67c73dcfae308625c87194025c0 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Wed, 9 Aug 2023 20:47:59 +0800 Subject: [PATCH 0980/3445] iommu/vt-d: Prepare for set_dev_pasid callback The domain_flush_pasid_iotlb() helper function is used to flush the IOTLB entries for a given PASID. Previously, this function assumed that RID2PASID was only used for the first-level DMA translation. However, with the introduction of the set_dev_pasid callback, this assumption is no longer valid. Add a check before using the RID2PASID for PASID invalidation. This check ensures that the domain has been attached to a physical device before using RID2PASID. Signed-off-by: Lu Baolu Signed-off-by: Jacob Pan Reviewed-by: Kevin Tian Link: https://lore.kernel.org/r/20230802212427.1497170-7-jacob.jun.pan@linux.intel.com Signed-off-by: Joerg Roedel --- drivers/iommu/intel/iommu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index 574021c36db56..19585800dcc90 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -1475,7 +1475,8 @@ static void domain_flush_pasid_iotlb(struct intel_iommu *iommu, unsigned long flags; spin_lock_irqsave(&domain->lock, flags); - qi_flush_piotlb(iommu, did, IOMMU_NO_PASID, addr, npages, ih); + if (!list_empty(&domain->devices)) + qi_flush_piotlb(iommu, did, IOMMU_NO_PASID, addr, npages, ih); spin_unlock_irqrestore(&domain->lock, flags); } -- GitLab From 7d0c9da6c1509664d96488042bacc02308ca33b2 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Wed, 9 Aug 2023 20:48:00 +0800 Subject: [PATCH 0981/3445] iommu/vt-d: Add set_dev_pasid callback for dma domain This allows the upper layers to set a domain to a PASID of a device if the PASID feature is supported by the IOMMU hardware. The typical use cases are, for example, kernel DMA with PASID and hardware assisted mediated device drivers. The attaching device and pasid information is tracked in a per-domain list and is used for IOTLB and devTLB invalidation. Signed-off-by: Lu Baolu Signed-off-by: Jacob Pan Reviewed-by: Kevin Tian Link: https://lore.kernel.org/r/20230802212427.1497170-8-jacob.jun.pan@linux.intel.com Signed-off-by: Joerg Roedel --- drivers/iommu/intel/iommu.c | 104 ++++++++++++++++++++++++++++++++++-- drivers/iommu/intel/iommu.h | 7 +++ 2 files changed, 106 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index 19585800dcc90..4b5ed58ee4228 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -1359,6 +1359,7 @@ domain_lookup_dev_info(struct dmar_domain *domain, static void domain_update_iotlb(struct dmar_domain *domain) { + struct dev_pasid_info *dev_pasid; struct device_domain_info *info; bool has_iotlb_device = false; unsigned long flags; @@ -1370,6 +1371,14 @@ static void domain_update_iotlb(struct dmar_domain *domain) break; } } + + list_for_each_entry(dev_pasid, &domain->dev_pasids, link_domain) { + info = dev_iommu_priv_get(dev_pasid->dev); + if (info->ats_enabled) { + has_iotlb_device = true; + break; + } + } domain->has_iotlb_device = has_iotlb_device; spin_unlock_irqrestore(&domain->lock, flags); } @@ -1455,6 +1464,7 @@ static void __iommu_flush_dev_iotlb(struct device_domain_info *info, static void iommu_flush_dev_iotlb(struct dmar_domain *domain, u64 addr, unsigned mask) { + struct dev_pasid_info *dev_pasid; struct device_domain_info *info; unsigned long flags; @@ -1464,6 +1474,19 @@ static void iommu_flush_dev_iotlb(struct dmar_domain *domain, spin_lock_irqsave(&domain->lock, flags); list_for_each_entry(info, &domain->devices, link) __iommu_flush_dev_iotlb(info, addr, mask); + + list_for_each_entry(dev_pasid, &domain->dev_pasids, link_domain) { + info = dev_iommu_priv_get(dev_pasid->dev); + + if (!info->ats_enabled) + continue; + + qi_flush_dev_iotlb_pasid(info->iommu, + PCI_DEVID(info->bus, info->devfn), + info->pfsid, dev_pasid->pasid, + info->ats_qdep, addr, + mask); + } spin_unlock_irqrestore(&domain->lock, flags); } @@ -1472,9 +1495,13 @@ static void domain_flush_pasid_iotlb(struct intel_iommu *iommu, unsigned long npages, bool ih) { u16 did = domain_id_iommu(domain, iommu); + struct dev_pasid_info *dev_pasid; unsigned long flags; spin_lock_irqsave(&domain->lock, flags); + list_for_each_entry(dev_pasid, &domain->dev_pasids, link_domain) + qi_flush_piotlb(iommu, did, dev_pasid->pasid, addr, npages, ih); + if (!list_empty(&domain->devices)) qi_flush_piotlb(iommu, did, IOMMU_NO_PASID, addr, npages, ih); spin_unlock_irqrestore(&domain->lock, flags); @@ -1739,6 +1766,7 @@ static struct dmar_domain *alloc_domain(unsigned int type) domain->use_first_level = true; domain->has_iotlb_device = false; INIT_LIST_HEAD(&domain->devices); + INIT_LIST_HEAD(&domain->dev_pasids); spin_lock_init(&domain->lock); xa_init(&domain->iommu_array); @@ -4726,7 +4754,10 @@ static void intel_iommu_iotlb_sync_map(struct iommu_domain *domain, static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid) { struct intel_iommu *iommu = device_to_iommu(dev, NULL, NULL); + struct dev_pasid_info *curr, *dev_pasid = NULL; + struct dmar_domain *dmar_domain; struct iommu_domain *domain; + unsigned long flags; domain = iommu_get_domain_for_dev_pasid(dev, pasid, 0); if (WARN_ON_ONCE(!domain)) @@ -4742,17 +4773,79 @@ static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid) goto out_tear_down; } - /* - * Should never reach here until we add support for attaching - * non-SVA domain to a pasid. - */ - WARN_ON(1); + dmar_domain = to_dmar_domain(domain); + spin_lock_irqsave(&dmar_domain->lock, flags); + list_for_each_entry(curr, &dmar_domain->dev_pasids, link_domain) { + if (curr->dev == dev && curr->pasid == pasid) { + list_del(&curr->link_domain); + dev_pasid = curr; + break; + } + } + WARN_ON_ONCE(!dev_pasid); + spin_unlock_irqrestore(&dmar_domain->lock, flags); + domain_detach_iommu(dmar_domain, iommu); + kfree(dev_pasid); out_tear_down: intel_pasid_tear_down_entry(iommu, dev, pasid, false); intel_drain_pasid_prq(dev, pasid); } +static int intel_iommu_set_dev_pasid(struct iommu_domain *domain, + struct device *dev, ioasid_t pasid) +{ + struct device_domain_info *info = dev_iommu_priv_get(dev); + struct dmar_domain *dmar_domain = to_dmar_domain(domain); + struct intel_iommu *iommu = info->iommu; + struct dev_pasid_info *dev_pasid; + unsigned long flags; + int ret; + + if (!pasid_supported(iommu) || dev_is_real_dma_subdevice(dev)) + return -EOPNOTSUPP; + + if (context_copied(iommu, info->bus, info->devfn)) + return -EBUSY; + + ret = prepare_domain_attach_device(domain, dev); + if (ret) + return ret; + + dev_pasid = kzalloc(sizeof(*dev_pasid), GFP_KERNEL); + if (!dev_pasid) + return -ENOMEM; + + ret = domain_attach_iommu(dmar_domain, iommu); + if (ret) + goto out_free; + + if (domain_type_is_si(dmar_domain)) + ret = intel_pasid_setup_pass_through(iommu, dmar_domain, + dev, pasid); + else if (dmar_domain->use_first_level) + ret = domain_setup_first_level(iommu, dmar_domain, + dev, pasid); + else + ret = intel_pasid_setup_second_level(iommu, dmar_domain, + dev, pasid); + if (ret) + goto out_detach_iommu; + + dev_pasid->dev = dev; + dev_pasid->pasid = pasid; + spin_lock_irqsave(&dmar_domain->lock, flags); + list_add(&dev_pasid->link_domain, &dmar_domain->dev_pasids); + spin_unlock_irqrestore(&dmar_domain->lock, flags); + + return 0; +out_detach_iommu: + domain_detach_iommu(dmar_domain, iommu); +out_free: + kfree(dev_pasid); + return ret; +} + const struct iommu_ops intel_iommu_ops = { .capable = intel_iommu_capable, .domain_alloc = intel_iommu_domain_alloc, @@ -4772,6 +4865,7 @@ const struct iommu_ops intel_iommu_ops = { #endif .default_domain_ops = &(const struct iommu_domain_ops) { .attach_dev = intel_iommu_attach_device, + .set_dev_pasid = intel_iommu_set_dev_pasid, .map_pages = intel_iommu_map_pages, .unmap_pages = intel_iommu_unmap_pages, .iotlb_sync_map = intel_iommu_iotlb_sync_map, diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h index 6d94a29f5d52e..c18fb699c87ac 100644 --- a/drivers/iommu/intel/iommu.h +++ b/drivers/iommu/intel/iommu.h @@ -595,6 +595,7 @@ struct dmar_domain { spinlock_t lock; /* Protect device tracking lists */ struct list_head devices; /* all devices' list */ + struct list_head dev_pasids; /* all attached pasids */ struct dma_pte *pgd; /* virtual address */ int gaw; /* max guest address width */ @@ -717,6 +718,12 @@ struct device_domain_info { struct pasid_table *pasid_table; /* pasid table */ }; +struct dev_pasid_info { + struct list_head link_domain; /* link to domain siblings */ + struct device *dev; + ioasid_t pasid; +}; + static inline void __iommu_flush_cache( struct intel_iommu *iommu, void *addr, int size) { -- GitLab From f5ccf55e10281ae4523b83fe87f2c27fd634dc9d Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Wed, 9 Aug 2023 20:48:01 +0800 Subject: [PATCH 0982/3445] dmaengine/idxd: Re-enable kernel workqueue under DMA API Kernel workqueues were disabled due to flawed use of kernel VA and SVA API. Now that we have the support for attaching PASID to the device's default domain and the ability to reserve global PASIDs from SVA APIs, we can re-enable the kernel work queues and use them under DMA API. We also use non-privileged access for in-kernel DMA to be consistent with the IOMMU settings. Consequently, interrupt for user privilege is enabled for work completion IRQs. Link: https://lore.kernel.org/linux-iommu/20210511194726.GP1002214@nvidia.com/ Tested-by: Tony Zhu Reviewed-by: Dave Jiang Reviewed-by: Fenghua Yu Reviewed-by: Lu Baolu Reviewed-by: Jason Gunthorpe Acked-by: Vinod Koul Signed-off-by: Jacob Pan Link: https://lore.kernel.org/r/20230802212427.1497170-9-jacob.jun.pan@linux.intel.com Signed-off-by: Lu Baolu Signed-off-by: Joerg Roedel --- drivers/dma/idxd/device.c | 39 ++++++++++------------------ drivers/dma/idxd/dma.c | 5 ++-- drivers/dma/idxd/idxd.h | 9 +++++++ drivers/dma/idxd/init.c | 54 ++++++++++++++++++++++++++++++++++++--- drivers/dma/idxd/sysfs.c | 7 ----- 5 files changed, 76 insertions(+), 38 deletions(-) diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index 5abbcc61c5288..169b7ade8919f 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -299,21 +299,6 @@ void idxd_wqs_unmap_portal(struct idxd_device *idxd) } } -static void __idxd_wq_set_priv_locked(struct idxd_wq *wq, int priv) -{ - struct idxd_device *idxd = wq->idxd; - union wqcfg wqcfg; - unsigned int offset; - - offset = WQCFG_OFFSET(idxd, wq->id, WQCFG_PRIVL_IDX); - spin_lock(&idxd->dev_lock); - wqcfg.bits[WQCFG_PRIVL_IDX] = ioread32(idxd->reg_base + offset); - wqcfg.priv = priv; - wq->wqcfg->bits[WQCFG_PRIVL_IDX] = wqcfg.bits[WQCFG_PRIVL_IDX]; - iowrite32(wqcfg.bits[WQCFG_PRIVL_IDX], idxd->reg_base + offset); - spin_unlock(&idxd->dev_lock); -} - static void __idxd_wq_set_pasid_locked(struct idxd_wq *wq, int pasid) { struct idxd_device *idxd = wq->idxd; @@ -1423,15 +1408,14 @@ int drv_enable_wq(struct idxd_wq *wq) } /* - * In the event that the WQ is configurable for pasid and priv bits. - * For kernel wq, the driver should setup the pasid, pasid_en, and priv bit. - * However, for non-kernel wq, the driver should only set the pasid_en bit for - * shared wq. A dedicated wq that is not 'kernel' type will configure pasid and + * In the event that the WQ is configurable for pasid, the driver + * should setup the pasid, pasid_en bit. This is true for both kernel + * and user shared workqueues. There is no need to setup priv bit in + * that in-kernel DMA will also do user privileged requests. + * A dedicated wq that is not 'kernel' type will configure pasid and * pasid_en later on so there is no need to setup. */ if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) { - int priv = 0; - if (wq_pasid_enabled(wq)) { if (is_idxd_wq_kernel(wq) || wq_shared(wq)) { u32 pasid = wq_dedicated(wq) ? idxd->pasid : 0; @@ -1439,10 +1423,6 @@ int drv_enable_wq(struct idxd_wq *wq) __idxd_wq_set_pasid_locked(wq, pasid); } } - - if (is_idxd_wq_kernel(wq)) - priv = 1; - __idxd_wq_set_priv_locked(wq, priv); } rc = 0; @@ -1550,6 +1530,15 @@ int idxd_device_drv_probe(struct idxd_dev *idxd_dev) if (rc < 0) return -ENXIO; + /* + * System PASID is preserved across device disable/enable cycle, but + * genconfig register content gets cleared during device reset. We + * need to re-enable user interrupts for kernel work queue completion + * IRQ to function. + */ + if (idxd->pasid != IOMMU_PASID_INVALID) + idxd_set_user_intr(idxd, 1); + rc = idxd_device_evl_setup(idxd); if (rc < 0) { idxd->cmd_status = IDXD_SCMD_DEV_EVL_ERR; diff --git a/drivers/dma/idxd/dma.c b/drivers/dma/idxd/dma.c index eb35ca3136845..07623fb0f52fc 100644 --- a/drivers/dma/idxd/dma.c +++ b/drivers/dma/idxd/dma.c @@ -75,9 +75,10 @@ static inline void idxd_prep_desc_common(struct idxd_wq *wq, hw->xfer_size = len; /* * For dedicated WQ, this field is ignored and HW will use the WQCFG.priv - * field instead. This field should be set to 1 for kernel descriptors. + * field instead. This field should be set to 0 for kernel descriptors + * since kernel DMA on VT-d supports "user" privilege only. */ - hw->priv = 1; + hw->priv = 0; hw->completion_addr = compl; } diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index 5428a2e1b1ec4..502be9db63f40 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -473,6 +473,15 @@ static inline struct idxd_device *ie_to_idxd(struct idxd_irq_entry *ie) return container_of(ie, struct idxd_device, ie); } +static inline void idxd_set_user_intr(struct idxd_device *idxd, bool enable) +{ + union gencfg_reg reg; + + reg.bits = ioread32(idxd->reg_base + IDXD_GENCFG_OFFSET); + reg.user_int_en = enable; + iowrite32(reg.bits, idxd->reg_base + IDXD_GENCFG_OFFSET); +} + extern struct bus_type dsa_bus_type; extern bool support_enqcmd; diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index 1aa823974cdac..0eb1c827a215f 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -550,14 +550,59 @@ static struct idxd_device *idxd_alloc(struct pci_dev *pdev, struct idxd_driver_d static int idxd_enable_system_pasid(struct idxd_device *idxd) { - return -EOPNOTSUPP; + struct pci_dev *pdev = idxd->pdev; + struct device *dev = &pdev->dev; + struct iommu_domain *domain; + ioasid_t pasid; + int ret; + + /* + * Attach a global PASID to the DMA domain so that we can use ENQCMDS + * to submit work on buffers mapped by DMA API. + */ + domain = iommu_get_domain_for_dev(dev); + if (!domain) + return -EPERM; + + pasid = iommu_alloc_global_pasid(dev); + if (pasid == IOMMU_PASID_INVALID) + return -ENOSPC; + + /* + * DMA domain is owned by the driver, it should support all valid + * types such as DMA-FQ, identity, etc. + */ + ret = iommu_attach_device_pasid(domain, dev, pasid); + if (ret) { + dev_err(dev, "failed to attach device pasid %d, domain type %d", + pasid, domain->type); + iommu_free_global_pasid(pasid); + return ret; + } + + /* Since we set user privilege for kernel DMA, enable completion IRQ */ + idxd_set_user_intr(idxd, 1); + idxd->pasid = pasid; + + return ret; } static void idxd_disable_system_pasid(struct idxd_device *idxd) { + struct pci_dev *pdev = idxd->pdev; + struct device *dev = &pdev->dev; + struct iommu_domain *domain; + + domain = iommu_get_domain_for_dev(dev); + if (!domain) + return; + + iommu_detach_device_pasid(domain, dev, idxd->pasid); + iommu_free_global_pasid(idxd->pasid); - iommu_sva_unbind_device(idxd->sva); + idxd_set_user_intr(idxd, 0); idxd->sva = NULL; + idxd->pasid = IOMMU_PASID_INVALID; } static int idxd_enable_sva(struct pci_dev *pdev) @@ -600,8 +645,9 @@ static int idxd_probe(struct idxd_device *idxd) } else { set_bit(IDXD_FLAG_USER_PASID_ENABLED, &idxd->flags); - if (idxd_enable_system_pasid(idxd)) - dev_warn(dev, "No in-kernel DMA with PASID.\n"); + rc = idxd_enable_system_pasid(idxd); + if (rc) + dev_warn(dev, "No in-kernel DMA with PASID. %d\n", rc); else set_bit(IDXD_FLAG_PASID_ENABLED, &idxd->flags); } diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index 293739ac55969..63f6966c51aa1 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -948,13 +948,6 @@ static ssize_t wq_name_store(struct device *dev, if (strlen(buf) > WQ_NAME_SIZE || strlen(buf) == 0) return -EINVAL; - /* - * This is temporarily placed here until we have SVM support for - * dmaengine. - */ - if (wq->type == IDXD_WQT_KERNEL && device_pasid_enabled(wq->idxd)) - return -EOPNOTSUPP; - input = kstrndup(buf, count, GFP_KERNEL); if (!input) return -ENOMEM; -- GitLab From a48ce36e2786f8bb33e9f42ea2d0c23ea4af3e0d Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Wed, 9 Aug 2023 20:48:02 +0800 Subject: [PATCH 0983/3445] iommu: Prevent RESV_DIRECT devices from blocking domains The IOMMU_RESV_DIRECT flag indicates that a memory region must be mapped 1:1 at all times. This means that the region must always be accessible to the device, even if the device is attached to a blocking domain. This is equal to saying that IOMMU_RESV_DIRECT flag prevents devices from being attached to blocking domains. This also implies that devices that implement RESV_DIRECT regions will be prevented from being assigned to user space since taking the DMA ownership immediately switches to a blocking domain. The rule of preventing devices with the IOMMU_RESV_DIRECT regions from being assigned to user space has existed in the Intel IOMMU driver for a long time. Now, this rule is being lifted up to a general core rule, as other architectures like AMD and ARM also have RMRR-like reserved regions. This has been discussed in the community mailing list and refer to below link for more details. Other places using unmanaged domains for kernel DMA must follow the iommu_get_resv_regions() and setup IOMMU_RESV_DIRECT - we do not restrict them in the core code. Cc: Robin Murphy Cc: Alex Williamson Cc: Kevin Tian Signed-off-by: Jason Gunthorpe Link: https://lore.kernel.org/linux-iommu/BN9PR11MB5276E84229B5BD952D78E9598C639@BN9PR11MB5276.namprd11.prod.outlook.com Signed-off-by: Lu Baolu Reviewed-by: Jason Gunthorpe Acked-by: Joerg Roedel Link: https://lore.kernel.org/r/20230724060352.113458-2-baolu.lu@linux.intel.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 37 +++++++++++++++++++++++++++---------- include/linux/iommu.h | 2 ++ 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index d199d144460c1..e385a99e25e1a 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -960,14 +960,12 @@ static int iommu_create_device_direct_mappings(struct iommu_domain *domain, unsigned long pg_size; int ret = 0; - if (!iommu_is_dma_domain(domain)) - return 0; - - BUG_ON(!domain->pgsize_bitmap); - - pg_size = 1UL << __ffs(domain->pgsize_bitmap); + pg_size = domain->pgsize_bitmap ? 1UL << __ffs(domain->pgsize_bitmap) : 0; INIT_LIST_HEAD(&mappings); + if (WARN_ON_ONCE(iommu_is_dma_domain(domain) && !pg_size)) + return -EINVAL; + iommu_get_resv_regions(dev, &mappings); /* We need to consider overlapping regions for different devices */ @@ -975,13 +973,17 @@ static int iommu_create_device_direct_mappings(struct iommu_domain *domain, dma_addr_t start, end, addr; size_t map_size = 0; - start = ALIGN(entry->start, pg_size); - end = ALIGN(entry->start + entry->length, pg_size); + if (entry->type == IOMMU_RESV_DIRECT) + dev->iommu->require_direct = 1; - if (entry->type != IOMMU_RESV_DIRECT && - entry->type != IOMMU_RESV_DIRECT_RELAXABLE) + if ((entry->type != IOMMU_RESV_DIRECT && + entry->type != IOMMU_RESV_DIRECT_RELAXABLE) || + !iommu_is_dma_domain(domain)) continue; + start = ALIGN(entry->start, pg_size); + end = ALIGN(entry->start + entry->length, pg_size); + for (addr = start; addr <= end; addr += pg_size) { phys_addr_t phys_addr; @@ -2122,6 +2124,21 @@ static int __iommu_device_set_domain(struct iommu_group *group, { int ret; + /* + * If the device requires IOMMU_RESV_DIRECT then we cannot allow + * the blocking domain to be attached as it does not contain the + * required 1:1 mapping. This test effectively excludes the device + * being used with iommu_group_claim_dma_owner() which will block + * vfio and iommufd as well. + */ + if (dev->iommu->require_direct && + (new_domain->type == IOMMU_DOMAIN_BLOCKED || + new_domain == group->blocking_domain)) { + dev_warn(dev, + "Firmware has requested this device have a 1:1 IOMMU mapping, rejecting configuring the device without a 1:1 mapping. Contact your platform vendor.\n"); + return -EINVAL; + } + if (dev->iommu->attach_deferred) { if (new_domain == group->default_domain) return 0; diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 6b821cb715d5a..54bae452975f8 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -411,6 +411,7 @@ struct iommu_fault_param { * @priv: IOMMU Driver private data * @max_pasids: number of PASIDs this device can consume * @attach_deferred: the dma domain attachment is deferred + * @require_direct: device requires IOMMU_RESV_DIRECT regions * * TODO: migrate other per device data pointers under iommu_dev_data, e.g. * struct iommu_group *iommu_group; @@ -424,6 +425,7 @@ struct dev_iommu { void *priv; u32 max_pasids; u32 attach_deferred:1; + u32 require_direct:1; }; int iommu_device_register(struct iommu_device *iommu, -- GitLab From d3aedf94f480971f7ffe88d337ba72e6f7d32497 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Wed, 9 Aug 2023 20:48:03 +0800 Subject: [PATCH 0984/3445] iommu/vt-d: Remove rmrr check in domain attaching device path The core code now prevents devices with RMRR regions from being assigned to user space. There is no need to check for this condition in individual drivers. Remove it to avoid duplicate code. Signed-off-by: Lu Baolu Reviewed-by: Jason Gunthorpe Reviewed-by: Kevin Tian Link: https://lore.kernel.org/r/20230724060352.113458-3-baolu.lu@linux.intel.com Signed-off-by: Joerg Roedel --- drivers/iommu/intel/iommu.c | 58 ------------------------------------- 1 file changed, 58 deletions(-) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index 4b5ed58ee4228..9369a8b02bd64 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -2487,30 +2487,6 @@ static int dmar_domain_attach_device(struct dmar_domain *domain, return 0; } -static bool device_has_rmrr(struct device *dev) -{ - struct dmar_rmrr_unit *rmrr; - struct device *tmp; - int i; - - rcu_read_lock(); - for_each_rmrr_units(rmrr) { - /* - * Return TRUE if this RMRR contains the device that - * is passed in. - */ - for_each_active_dev_scope(rmrr->devices, - rmrr->devices_cnt, i, tmp) - if (tmp == dev || - is_downstream_to_pci_bridge(dev, tmp)) { - rcu_read_unlock(); - return true; - } - } - rcu_read_unlock(); - return false; -} - /** * device_rmrr_is_relaxable - Test whether the RMRR of this device * is relaxable (ie. is allowed to be not enforced under some conditions) @@ -2540,34 +2516,6 @@ static bool device_rmrr_is_relaxable(struct device *dev) return false; } -/* - * There are a couple cases where we need to restrict the functionality of - * devices associated with RMRRs. The first is when evaluating a device for - * identity mapping because problems exist when devices are moved in and out - * of domains and their respective RMRR information is lost. This means that - * a device with associated RMRRs will never be in a "passthrough" domain. - * The second is use of the device through the IOMMU API. This interface - * expects to have full control of the IOVA space for the device. We cannot - * satisfy both the requirement that RMRR access is maintained and have an - * unencumbered IOVA space. We also have no ability to quiesce the device's - * use of the RMRR space or even inform the IOMMU API user of the restriction. - * We therefore prevent devices associated with an RMRR from participating in - * the IOMMU API, which eliminates them from device assignment. - * - * In both cases, devices which have relaxable RMRRs are not concerned by this - * restriction. See device_rmrr_is_relaxable comment. - */ -static bool device_is_rmrr_locked(struct device *dev) -{ - if (!device_has_rmrr(dev)) - return false; - - if (device_rmrr_is_relaxable(dev)) - return false; - - return true; -} - /* * Return the required default domain type for a specific device. * @@ -4180,12 +4128,6 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, struct device_domain_info *info = dev_iommu_priv_get(dev); int ret; - if (domain->type == IOMMU_DOMAIN_UNMANAGED && - device_is_rmrr_locked(dev)) { - dev_warn(dev, "Device is ineligible for IOMMU domain attach due to platform RMRR requirement. Contact your platform vendor.\n"); - return -EPERM; - } - if (info->domain) device_block_translation(dev); -- GitLab From 8a3b8e63f8371c1247b7aa24ff9c5312f1a6948b Mon Sep 17 00:00:00 2001 From: Yanfei Xu Date: Wed, 9 Aug 2023 20:48:04 +0800 Subject: [PATCH 0985/3445] iommu/vt-d: Fix to flush cache of PASID directory table Even the PCI devices don't support pasid capability, PASID table is mandatory for a PCI device in scalable mode. However flushing cache of pasid directory table for these devices are not taken after pasid table is allocated as the "size" of table is zero. Fix it by calculating the size by page order. Found this when reading the code, no real problem encountered for now. Fixes: 194b3348bdbb ("iommu/vt-d: Fix PASID directory pointer coherency") Suggested-by: Lu Baolu Signed-off-by: Yanfei Xu Link: https://lore.kernel.org/r/20230616081045.721873-1-yanfei.xu@intel.com Signed-off-by: Lu Baolu Signed-off-by: Joerg Roedel --- drivers/iommu/intel/pasid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c index 23dca3bc319d8..8f92b92f3d2ab 100644 --- a/drivers/iommu/intel/pasid.c +++ b/drivers/iommu/intel/pasid.c @@ -129,7 +129,7 @@ int intel_pasid_alloc_table(struct device *dev) info->pasid_table = pasid_table; if (!ecap_coherent(info->iommu->ecap)) - clflush_cache_range(pasid_table->table, size); + clflush_cache_range(pasid_table->table, (1 << order) * PAGE_SIZE); return 0; } -- GitLab From fb5f50a43d9fd44fd6bc4f4dbcf9d3ec5b556558 Mon Sep 17 00:00:00 2001 From: Yanfei Xu Date: Wed, 9 Aug 2023 20:48:05 +0800 Subject: [PATCH 0986/3445] iommu/vt-d: Fix to convert mm pfn to dma pfn For the case that VT-d page is smaller than mm page, converting dma pfn should be handled in two cases which are for start pfn and for end pfn. Currently the calculation of end dma pfn is incorrect and the result is less than real page frame number which is causing the mapping of iova always misses some page frames. Rename the mm_to_dma_pfn() to mm_to_dma_pfn_start() and add a new helper for converting end dma pfn named mm_to_dma_pfn_end(). Signed-off-by: Yanfei Xu Link: https://lore.kernel.org/r/20230625082046.979742-1-yanfei.xu@intel.com Signed-off-by: Lu Baolu Signed-off-by: Joerg Roedel --- drivers/iommu/intel/iommu.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index 9369a8b02bd64..dbf9270e565e8 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -113,13 +113,17 @@ static inline unsigned long lvl_to_nr_pages(unsigned int lvl) /* VT-d pages must always be _smaller_ than MM pages. Otherwise things are never going to work. */ -static inline unsigned long mm_to_dma_pfn(unsigned long mm_pfn) +static inline unsigned long mm_to_dma_pfn_start(unsigned long mm_pfn) { return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT); } +static inline unsigned long mm_to_dma_pfn_end(unsigned long mm_pfn) +{ + return ((mm_pfn + 1) << (PAGE_SHIFT - VTD_PAGE_SHIFT)) - 1; +} static inline unsigned long page_to_dma_pfn(struct page *pg) { - return mm_to_dma_pfn(page_to_pfn(pg)); + return mm_to_dma_pfn_start(page_to_pfn(pg)); } static inline unsigned long virt_to_dma_pfn(void *p) { @@ -2403,8 +2407,8 @@ static int __init si_domain_init(int hw) for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) { ret = iommu_domain_identity_map(si_domain, - mm_to_dma_pfn(start_pfn), - mm_to_dma_pfn(end_pfn)); + mm_to_dma_pfn_start(start_pfn), + mm_to_dma_pfn_end(end_pfn)); if (ret) return ret; } @@ -2425,8 +2429,8 @@ static int __init si_domain_init(int hw) continue; ret = iommu_domain_identity_map(si_domain, - mm_to_dma_pfn(start >> PAGE_SHIFT), - mm_to_dma_pfn(end >> PAGE_SHIFT)); + mm_to_dma_pfn_start(start >> PAGE_SHIFT), + mm_to_dma_pfn_end(end >> PAGE_SHIFT)); if (ret) return ret; } @@ -3549,8 +3553,8 @@ static int intel_iommu_memory_notifier(struct notifier_block *nb, unsigned long val, void *v) { struct memory_notify *mhp = v; - unsigned long start_vpfn = mm_to_dma_pfn(mhp->start_pfn); - unsigned long last_vpfn = mm_to_dma_pfn(mhp->start_pfn + + unsigned long start_vpfn = mm_to_dma_pfn_start(mhp->start_pfn); + unsigned long last_vpfn = mm_to_dma_pfn_end(mhp->start_pfn + mhp->nr_pages - 1); switch (val) { @@ -4254,7 +4258,7 @@ static void intel_iommu_tlb_sync(struct iommu_domain *domain, unsigned long i; nrpages = aligned_nrpages(gather->start, size); - start_pfn = mm_to_dma_pfn(iova_pfn); + start_pfn = mm_to_dma_pfn_start(iova_pfn); xa_for_each(&dmar_domain->iommu_array, i, info) iommu_flush_iotlb_psi(info->iommu, dmar_domain, -- GitLab From cb4396e0d8c498dcd50974ca931a176e5fa1e3fa Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 9 Aug 2023 20:48:06 +0800 Subject: [PATCH 0987/3445] iommu/vt-d: Remove unused extern declaration dmar_parse_dev_scope() Since commit 2e4552893038 ("iommu/vt-d: Unify the way to process DMAR device scope array") this is not used anymore, so can remove it. Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20230802133934.19712-1-yuehaibing@huawei.com Signed-off-by: Lu Baolu Signed-off-by: Joerg Roedel --- include/linux/dmar.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/dmar.h b/include/linux/dmar.h index 27dbd4c64860b..e34b601b71fd2 100644 --- a/include/linux/dmar.h +++ b/include/linux/dmar.h @@ -106,8 +106,6 @@ static inline bool dmar_rcu_check(void) extern int dmar_table_init(void); extern int dmar_dev_scope_init(void); extern void dmar_register_bus_notifier(void); -extern int dmar_parse_dev_scope(void *start, void *end, int *cnt, - struct dmar_dev_scope **devices, u16 segment); extern void *dmar_alloc_dev_scope(void *start, void *end, int *cnt); extern void dmar_free_dev_scope(struct dmar_dev_scope **devices, int *cnt); extern int dmar_insert_dev_scope(struct dmar_pci_notify_info *info, -- GitLab From a69c610e13e2b2de8a1ed2683f13e21b3200bd7a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 1 Aug 2023 12:59:15 +0200 Subject: [PATCH 0988/3445] rtc: stm32: remove incorrect #ifdef check After a previous commit changed the driver over to SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(), the suspend/resume functions must no longer be hidden behind an #ifdef: In file included from include/linux/clk.h:13, from drivers/rtc/rtc-stm32.c:8: drivers/rtc/rtc-stm32.c:927:39: error: 'stm32_rtc_suspend' undeclared here (not in a function); did you mean 'stm32_rtc_probe'? 927 | SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_rtc_suspend, stm32_rtc_resume) | ^~~~~~~~~~~~~~~~~ include/linux/kernel.h:58:44: note: in definition of macro 'PTR_IF' 58 | #define PTR_IF(cond, ptr) ((cond) ? (ptr) : NULL) | ^~~ include/linux/pm.h:329:26: note: in expansion of macro 'pm_sleep_ptr' 329 | .suspend_noirq = pm_sleep_ptr(suspend_fn), \ | ^~~~~~~~~~~~ Fixes: fb9a7e5360dc8 ("rtc: stm32: change PM callbacks to "_noirq()"") Signed-off-by: Arnd Bergmann Reviewed-by: Valentin Caron Link: https://lore.kernel.org/r/20230801105932.3738430-1-arnd@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stm32.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index 3ae875b19af82..3ce4b3d08155b 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -891,7 +891,6 @@ static void stm32_rtc_remove(struct platform_device *pdev) device_init_wakeup(&pdev->dev, false); } -#ifdef CONFIG_PM_SLEEP static int stm32_rtc_suspend(struct device *dev) { struct stm32_rtc *rtc = dev_get_drvdata(dev); @@ -922,7 +921,6 @@ static int stm32_rtc_resume(struct device *dev) return ret; } -#endif static const struct dev_pm_ops stm32_rtc_pm_ops = { SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_rtc_suspend, stm32_rtc_resume) -- GitLab From df9c16b5ccc8e4aab5e492b5f110167c75c74b0a Mon Sep 17 00:00:00 2001 From: Chen Jiahao Date: Wed, 2 Aug 2023 17:36:50 +0800 Subject: [PATCH 0989/3445] rtc: sunplus: Clean up redundant dev_err_probe() Referring to platform_get_irq()'s definition, the return value has already been checked if ret < 0, and printed via dev_err_probe(). Calling dev_err_probe() one more time outside platform_get_irq() is obviously redundant. Removing dev_err_probe() outside platform_get_irq() to clean up above problem. Signed-off-by: Chen Jiahao Link: https://lore.kernel.org/r/20230802093650.976352-1-chenjiahao16@huawei.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sunplus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-sunplus.c b/drivers/rtc/rtc-sunplus.c index f33dc301f3019..20c7e97c2fc81 100644 --- a/drivers/rtc/rtc-sunplus.c +++ b/drivers/rtc/rtc-sunplus.c @@ -244,7 +244,7 @@ static int sp_rtc_probe(struct platform_device *plat_dev) sp_rtc->irq = platform_get_irq(plat_dev, 0); if (sp_rtc->irq < 0) - return dev_err_probe(&plat_dev->dev, sp_rtc->irq, "platform_get_irq failed\n"); + return sp_rtc->irq; ret = devm_request_irq(&plat_dev->dev, sp_rtc->irq, sp_rtc_irq_handler, IRQF_TRIGGER_RISING, "rtc irq", plat_dev); -- GitLab From cbf871e6d8ce23dd4d458d8b7ab9d4a267e7bc03 Mon Sep 17 00:00:00 2001 From: Billy Tsai Date: Wed, 2 Aug 2023 18:09:09 +0800 Subject: [PATCH 0990/3445] i3c/master: cmd_v1: Fix the exit criteria for the daa procedure The exit criteria for the DAA should check if the data length is equal to 1, instead of checking if the response status is equal to 1. Signed-off-by: Billy Tsai Link: https://lore.kernel.org/r/20230802100909.2568215-1-billy_tsai@aspeedtech.com Signed-off-by: Alexandre Belloni --- drivers/i3c/master/mipi-i3c-hci/cmd_v1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c b/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c index d97c3175e0e27..6a781f89b0e40 100644 --- a/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c +++ b/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c @@ -339,7 +339,7 @@ static int hci_cmd_v1_daa(struct i3c_hci *hci) break; } if (RESP_STATUS(xfer[0].response) == RESP_ERR_NACK && - RESP_STATUS(xfer[0].response) == 1) { + RESP_DATA_LENGTH(xfer->response) == 1) { ret = 0; /* no more devices to be assigned */ break; } -- GitLab From 4f3688dca15053555ade31a785a9c75837a64fb8 Mon Sep 17 00:00:00 2001 From: Zhu Wang Date: Tue, 8 Aug 2023 19:52:09 +0800 Subject: [PATCH 0991/3445] rtc: remove redundant of_match_ptr() Signed-off-by: Zhu Wang Link: https://lore.kernel.org/r/20230808115213.154377-2-wangzhu9@huawei.com Link: https://lore.kernel.org/r/20230808115213.154377-3-wangzhu9@huawei.com Link: https://lore.kernel.org/r/20230808115213.154377-4-wangzhu9@huawei.com Link: https://lore.kernel.org/r/20230808115213.154377-5-wangzhu9@huawei.com Link: https://lore.kernel.org/r/20230808115213.154377-6-wangzhu9@huawei.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-armada38x.c | 4 +--- drivers/rtc/rtc-aspeed.c | 2 +- drivers/rtc/rtc-at91rm9200.c | 2 +- drivers/rtc/rtc-at91sam9.c | 2 +- drivers/rtc/rtc-nct3018y.c | 2 +- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c index 8abcad38b10c2..569c1054d6b0b 100644 --- a/drivers/rtc/rtc-armada38x.c +++ b/drivers/rtc/rtc-armada38x.c @@ -473,7 +473,6 @@ static const struct armada38x_rtc_data armada8k_data = { .alarm = ALARM2, }; -#ifdef CONFIG_OF static const struct of_device_id armada38x_rtc_of_match_table[] = { { .compatible = "marvell,armada-380-rtc", @@ -486,7 +485,6 @@ static const struct of_device_id armada38x_rtc_of_match_table[] = { {} }; MODULE_DEVICE_TABLE(of, armada38x_rtc_of_match_table); -#endif static __init int armada38x_rtc_probe(struct platform_device *pdev) { @@ -576,7 +574,7 @@ static struct platform_driver armada38x_rtc_driver = { .driver = { .name = "armada38x-rtc", .pm = &armada38x_rtc_pm_ops, - .of_match_table = of_match_ptr(armada38x_rtc_of_match_table), + .of_match_table = armada38x_rtc_of_match_table, }, }; diff --git a/drivers/rtc/rtc-aspeed.c b/drivers/rtc/rtc-aspeed.c index a93352ed3aec9..880b015eebaf7 100644 --- a/drivers/rtc/rtc-aspeed.c +++ b/drivers/rtc/rtc-aspeed.c @@ -118,7 +118,7 @@ MODULE_DEVICE_TABLE(of, aspeed_rtc_match); static struct platform_driver aspeed_rtc_driver = { .driver = { .name = "aspeed-rtc", - .of_match_table = of_match_ptr(aspeed_rtc_match), + .of_match_table = aspeed_rtc_match, }, }; diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index 245588a7b417c..add4f71d7b3b9 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -641,7 +641,7 @@ static struct platform_driver at91_rtc_driver = { .driver = { .name = "at91_rtc", .pm = &at91_rtc_pm_ops, - .of_match_table = of_match_ptr(at91_rtc_dt_ids), + .of_match_table = at91_rtc_dt_ids, }, }; diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 610f27dfc462d..f93bee96e3623 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -534,7 +534,7 @@ static struct platform_driver at91_rtc_driver = { .driver = { .name = "rtc-at91sam9", .pm = &at91_rtc_pm_ops, - .of_match_table = of_match_ptr(at91_rtc_dt_ids), + .of_match_table = at91_rtc_dt_ids, }, }; diff --git a/drivers/rtc/rtc-nct3018y.c b/drivers/rtc/rtc-nct3018y.c index a4e3f924837e0..ed4e606be8e58 100644 --- a/drivers/rtc/rtc-nct3018y.c +++ b/drivers/rtc/rtc-nct3018y.c @@ -538,7 +538,7 @@ MODULE_DEVICE_TABLE(of, nct3018y_of_match); static struct i2c_driver nct3018y_driver = { .driver = { .name = "rtc-nct3018y", - .of_match_table = of_match_ptr(nct3018y_of_match), + .of_match_table = nct3018y_of_match, }, .probe = nct3018y_probe, .id_table = nct3018y_id, -- GitLab From 7aec2f39a1a4be99a7872e2342a69b96396c3e0c Mon Sep 17 00:00:00 2001 From: Liao Chang Date: Tue, 8 Aug 2023 09:29:46 +0800 Subject: [PATCH 0992/3445] i2c: bcm2835: Use dev_err_probe in probe function Use the dev_err_probe function instead of dev_err in the probe function so that the printed message includes the return value and also handles -EPROBE_DEFER nicely. Signed-off-by: Liao Chang Reviewed-by: Florian Fainelli Link: https://lore.kernel.org/r/20230808012954.1643834-2-liaochang1@huawei.com Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-bcm2835.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index 8ce6d3f495516..9af1a68269ab0 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -430,10 +430,9 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) i2c_dev->bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk, i2c_dev); - if (IS_ERR(i2c_dev->bus_clk)) { - dev_err(&pdev->dev, "Could not register clock\n"); - return PTR_ERR(i2c_dev->bus_clk); - } + if (IS_ERR(i2c_dev->bus_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2c_dev->bus_clk), + "Could not register clock\n"); ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency", &bus_clk_rate); @@ -444,10 +443,9 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) } ret = clk_set_rate_exclusive(i2c_dev->bus_clk, bus_clk_rate); - if (ret < 0) { - dev_err(&pdev->dev, "Could not set clock frequency\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "Could not set clock frequency\n"); ret = clk_prepare_enable(i2c_dev->bus_clk); if (ret) { -- GitLab From 45a7a0524bff52360f82277f165bbdef7a199484 Mon Sep 17 00:00:00 2001 From: Liao Chang Date: Tue, 8 Aug 2023 09:29:47 +0800 Subject: [PATCH 0993/3445] i2c: mlxbf: Use dev_err_probe in probe function Use the dev_err_probe function instead of dev_err in the probe function so that the printed message includes the return value and also handles -EPROBE_DEFER nicely. Signed-off-by: Liao Chang Reviewed-by: Andi Shyti Link: https://lore.kernel.org/r/20230808012954.1643834-3-liaochang1@huawei.com Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-mlxbf.c | 50 ++++++++++++---------------------- 1 file changed, 17 insertions(+), 33 deletions(-) diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c index ae66bdd1b7379..5ee82016c8050 100644 --- a/drivers/i2c/busses/i2c-mlxbf.c +++ b/drivers/i2c/busses/i2c-mlxbf.c @@ -2323,10 +2323,8 @@ static int mlxbf_i2c_probe(struct platform_device *pdev) ret = mlxbf_i2c_init_resource(pdev, &priv->smbus, MLXBF_I2C_SMBUS_RES); - if (ret < 0) { - dev_err(dev, "Cannot fetch smbus resource info"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Cannot fetch smbus resource info"); priv->timer->io = priv->smbus->io; priv->mst->io = priv->smbus->io + MLXBF_I2C_MST_ADDR_OFFSET; @@ -2334,39 +2332,29 @@ static int mlxbf_i2c_probe(struct platform_device *pdev) } else { ret = mlxbf_i2c_init_resource(pdev, &priv->timer, MLXBF_I2C_SMBUS_TIMER_RES); - if (ret < 0) { - dev_err(dev, "Cannot fetch timer resource info"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Cannot fetch timer resource info"); ret = mlxbf_i2c_init_resource(pdev, &priv->mst, MLXBF_I2C_SMBUS_MST_RES); - if (ret < 0) { - dev_err(dev, "Cannot fetch master resource info"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Cannot fetch master resource info"); ret = mlxbf_i2c_init_resource(pdev, &priv->slv, MLXBF_I2C_SMBUS_SLV_RES); - if (ret < 0) { - dev_err(dev, "Cannot fetch slave resource info"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Cannot fetch slave resource info"); } ret = mlxbf_i2c_init_resource(pdev, &priv->mst_cause, MLXBF_I2C_MST_CAUSE_RES); - if (ret < 0) { - dev_err(dev, "Cannot fetch cause master resource info"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Cannot fetch cause master resource info"); ret = mlxbf_i2c_init_resource(pdev, &priv->slv_cause, MLXBF_I2C_SLV_CAUSE_RES); - if (ret < 0) { - dev_err(dev, "Cannot fetch cause slave resource info"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Cannot fetch cause slave resource info"); adap = &priv->adap; adap->owner = THIS_MODULE; @@ -2397,11 +2385,9 @@ static int mlxbf_i2c_probe(struct platform_device *pdev) * does not really hurt, then keep the code as is. */ ret = mlxbf_i2c_init_master(pdev, priv); - if (ret < 0) { - dev_err(dev, "failed to initialize smbus master %d", - priv->bus); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "failed to initialize smbus master %d", + priv->bus); mlxbf_i2c_init_timings(pdev, priv); @@ -2413,10 +2399,8 @@ static int mlxbf_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, mlxbf_i2c_irq, IRQF_SHARED | IRQF_PROBE_SHARED, dev_name(dev), priv); - if (ret < 0) { - dev_err(dev, "Cannot get irq %d\n", irq); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Cannot get irq %d\n", irq); priv->irq = irq; -- GitLab From 300098637900f7ff99cafed2be7221407b82df83 Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Thu, 3 Aug 2023 16:51:49 +0800 Subject: [PATCH 0994/3445] i3c: master: svc: Do not check for 0 return after calling platform_get_irq() It is not possible for platform_get_irq() to return 0. Use the return value from platform_get_irq(). Signed-off-by: Ruan Jinjie Reviewed-by: Miquel Raynal Link: https://lore.kernel.org/r/20230803085149.149248-1-ruanjinjie@huawei.com Signed-off-by: Alexandre Belloni --- drivers/i3c/master/svc-i3c-master.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c index 0d63b732ef0c8..770b40e28015e 100644 --- a/drivers/i3c/master/svc-i3c-master.c +++ b/drivers/i3c/master/svc-i3c-master.c @@ -1518,8 +1518,8 @@ static int svc_i3c_master_probe(struct platform_device *pdev) return PTR_ERR(master->sclk); master->irq = platform_get_irq(pdev, 0); - if (master->irq <= 0) - return -ENOENT; + if (master->irq < 0) + return master->irq; master->dev = dev; -- GitLab From 9a648b3f56c49551081b9560392e9a640aa3d5cb Mon Sep 17 00:00:00 2001 From: Liao Chang Date: Tue, 8 Aug 2023 09:29:48 +0800 Subject: [PATCH 0995/3445] i2c: xlp9xx: Use dev_err_probe in probe function Use the dev_err_probe function instead of dev_err in the probe function so that the printed message includes the return value and also handles -EPROBE_DEFER nicely. Signed-off-by: Liao Chang Reviewed-by: Andi Shyti Link: https://lore.kernel.org/r/20230808012954.1643834-4-liaochang1@huawei.com Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-xlp9xx.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index f59e8c544f366..08a59a920929f 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -529,10 +529,8 @@ static int xlp9xx_i2c_probe(struct platform_device *pdev) err = devm_request_irq(&pdev->dev, priv->irq, xlp9xx_i2c_isr, 0, pdev->name, priv); - if (err) { - dev_err(&pdev->dev, "IRQ request failed!\n"); - return err; - } + if (err) + return dev_err_probe(&pdev->dev, err, "IRQ request failed!\n"); init_completion(&priv->msg_complete); priv->adapter.dev.parent = &pdev->dev; -- GitLab From 3c5e6ae40164ba6af1efaa1ca94e2cdea0c8f25e Mon Sep 17 00:00:00 2001 From: Liao Chang Date: Tue, 8 Aug 2023 09:29:49 +0800 Subject: [PATCH 0996/3445] i2c: hisi: Use dev_err_probe in probe function Use the dev_err_probe function instead of dev_err in the probe function so that the printed message includes the return value and also handles -EPROBE_DEFER nicely. Signed-off-by: Liao Chang Reviewed-by: Yicong Yang Link: https://lore.kernel.org/r/20230808012954.1643834-5-liaochang1@huawei.com Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-hisi.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/busses/i2c-hisi.c b/drivers/i2c/busses/i2c-hisi.c index e067671b3ce2e..6fc8d6fa43b64 100644 --- a/drivers/i2c/busses/i2c-hisi.c +++ b/drivers/i2c/busses/i2c-hisi.c @@ -462,18 +462,14 @@ static int hisi_i2c_probe(struct platform_device *pdev) hisi_i2c_disable_int(ctlr, HISI_I2C_INT_ALL); ret = devm_request_irq(dev, ctlr->irq, hisi_i2c_irq, 0, "hisi-i2c", ctlr); - if (ret) { - dev_err(dev, "failed to request irq handler, ret = %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to request irq handler\n"); ctlr->clk = devm_clk_get_optional_enabled(&pdev->dev, NULL); if (IS_ERR_OR_NULL(ctlr->clk)) { ret = device_property_read_u64(dev, "clk_rate", &clk_rate_hz); - if (ret) { - dev_err(dev, "failed to get clock frequency, ret = %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to get clock frequency\n"); } else { clk_rate_hz = clk_get_rate(ctlr->clk); } -- GitLab From 605efbf43813857d8110ca0b5bda75f93426a789 Mon Sep 17 00:00:00 2001 From: Liao Chang Date: Tue, 8 Aug 2023 09:29:50 +0800 Subject: [PATCH 0997/3445] i2c: qcom-cci: Use dev_err_probe in probe function Use the dev_err_probe function instead of dev_err in the probe function so that the printed message includes the return value and also handles -EPROBE_DEFER nicely. Signed-off-by: Liao Chang Reviewed-by: Andi Shyti Link: https://lore.kernel.org/r/20230808012954.1643834-6-liaochang1@huawei.com Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-qcom-cci.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c index 622dc14add9d7..cf13abec05f15 100644 --- a/drivers/i2c/busses/i2c-qcom-cci.c +++ b/drivers/i2c/busses/i2c-qcom-cci.c @@ -588,10 +588,8 @@ static int cci_probe(struct platform_device *pdev) /* Clocks */ ret = devm_clk_bulk_get_all(dev, &cci->clocks); - if (ret < 1) { - dev_err(dev, "failed to get clocks %d\n", ret); - return ret; - } + if (ret < 1) + return dev_err_probe(dev, ret, "failed to get clocks\n"); cci->nclocks = ret; /* Retrieve CCI clock rate */ -- GitLab From d29066600a85b15077221be404a38d9c4bf5b888 Mon Sep 17 00:00:00 2001 From: Liao Chang Date: Tue, 8 Aug 2023 09:29:51 +0800 Subject: [PATCH 0998/3445] i2c: pxa: Use dev_err_probe in probe function Use the dev_err_probe function instead of dev_err in the probe function so that the printed message includes the return value and also handles -EPROBE_DEFER nicely. Signed-off-by: Liao Chang Reviewed-by: Andi Shyti Link: https://lore.kernel.org/r/20230808012954.1643834-7-liaochang1@huawei.com Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-pxa.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 65a18d73be5c5..2eae12c048541 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1404,10 +1404,9 @@ static int i2c_pxa_probe(struct platform_device *dev) strscpy(i2c->adap.name, "pxa_i2c-i2c", sizeof(i2c->adap.name)); i2c->clk = devm_clk_get(&dev->dev, NULL); - if (IS_ERR(i2c->clk)) { - dev_err(&dev->dev, "failed to get the clk: %ld\n", PTR_ERR(i2c->clk)); - return PTR_ERR(i2c->clk); - } + if (IS_ERR(i2c->clk)) + return dev_err_probe(&dev->dev, PTR_ERR(i2c->clk), + "failed to get the clk\n"); i2c->reg_ibmr = i2c->reg_base + pxa_reg_layout[i2c_type].ibmr; i2c->reg_idbr = i2c->reg_base + pxa_reg_layout[i2c_type].idbr; -- GitLab From 235712aa7ebf75a8442905ae672c02a4f9f8468c Mon Sep 17 00:00:00 2001 From: Liao Chang Date: Tue, 8 Aug 2023 09:29:52 +0800 Subject: [PATCH 0999/3445] i2c: dln2: Use dev_err_probe in probe function Use the dev_err_probe function instead of dev_err in the probe function so that the printed message includes the return value and also handles -EPROBE_DEFER nicely. Signed-off-by: Liao Chang Reviewed-by: Andi Shyti Link: https://lore.kernel.org/r/20230808012954.1643834-8-liaochang1@huawei.com Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-dln2.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-dln2.c b/drivers/i2c/busses/i2c-dln2.c index 4f02cc2fb5675..631109c7a0988 100644 --- a/drivers/i2c/busses/i2c-dln2.c +++ b/drivers/i2c/busses/i2c-dln2.c @@ -218,10 +218,8 @@ static int dln2_i2c_probe(struct platform_device *pdev) /* initialize the i2c interface */ ret = dln2_i2c_enable(dln2, true); - if (ret < 0) { - dev_err(dev, "failed to initialize adapter: %d\n", ret); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "failed to initialize adapter\n"); /* and finally attach to i2c layer */ ret = i2c_add_adapter(&dln2->adapter); -- GitLab From 5d51af11f41eb348d9c3ccb5c74ffa9078673166 Mon Sep 17 00:00:00 2001 From: Liao Chang Date: Tue, 8 Aug 2023 09:29:53 +0800 Subject: [PATCH 1000/3445] i2c: imx-lpi2c: Use dev_err_probe in probe function Use the dev_err_probe function instead of dev_err in the probe function so that the printed message includes the return value and also handles -EPROBE_DEFER nicely. Signed-off-by: Liao Chang Reviewed-by: Andi Shyti Link: https://lore.kernel.org/r/20230808012954.1643834-9-liaochang1@huawei.com Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-imx-lpi2c.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index 636ad32479829..0af286d934bd5 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -567,10 +567,8 @@ static int lpi2c_imx_probe(struct platform_device *pdev) sizeof(lpi2c_imx->adapter.name)); ret = devm_clk_bulk_get_all(&pdev->dev, &lpi2c_imx->clks); - if (ret < 0) { - dev_err(&pdev->dev, "can't get I2C peripheral clock, ret=%d\n", ret); - return ret; - } + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "can't get I2C peripheral clock\n"); lpi2c_imx->num_clks = ret; ret = of_property_read_u32(pdev->dev.of_node, @@ -580,10 +578,8 @@ static int lpi2c_imx_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, irq, lpi2c_imx_isr, 0, pdev->name, lpi2c_imx); - if (ret) { - dev_err(&pdev->dev, "can't claim irq %d\n", irq); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "can't claim irq %d\n", irq); i2c_set_adapdata(&lpi2c_imx->adapter, lpi2c_imx); platform_set_drvdata(pdev, lpi2c_imx); -- GitLab From 7a34bab2daeaae6d2f32bdfa20b876a8f210cd7a Mon Sep 17 00:00:00 2001 From: Liao Chang Date: Tue, 8 Aug 2023 09:29:54 +0800 Subject: [PATCH 1001/3445] i2c: synquacer: Use dev_err_probe in probe function Use the dev_err_probe function instead of dev_err in the probe function so that the printed message includes the return value and also handles -EPROBE_DEFER nicely. Signed-off-by: Liao Chang Reviewed-by: Andi Shyti Link: https://lore.kernel.org/r/20230808012954.1643834-10-liaochang1@huawei.com Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-synquacer.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/drivers/i2c/busses/i2c-synquacer.c b/drivers/i2c/busses/i2c-synquacer.c index 4cc196ca8f6dc..bbea521b05dda 100644 --- a/drivers/i2c/busses/i2c-synquacer.c +++ b/drivers/i2c/busses/i2c-synquacer.c @@ -557,20 +557,16 @@ static int synquacer_i2c_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "clock source %p\n", i2c->pclk); ret = clk_prepare_enable(i2c->pclk); - if (ret) { - dev_err(&pdev->dev, "failed to enable clock (%d)\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "failed to enable clock\n"); i2c->pclkrate = clk_get_rate(i2c->pclk); } if (i2c->pclkrate < SYNQUACER_I2C_MIN_CLK_RATE || - i2c->pclkrate > SYNQUACER_I2C_MAX_CLK_RATE) { - dev_err(&pdev->dev, "PCLK missing or out of range (%d)\n", - i2c->pclkrate); - return -EINVAL; - } + i2c->pclkrate > SYNQUACER_I2C_MAX_CLK_RATE) + return dev_err_probe(&pdev->dev, -EINVAL, + "PCLK missing or out of range (%d)\n", + i2c->pclkrate); i2c->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(i2c->base)) @@ -582,10 +578,8 @@ static int synquacer_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, i2c->irq, synquacer_i2c_isr, 0, dev_name(&pdev->dev), i2c); - if (ret < 0) { - dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq); - return ret; - } + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "cannot claim IRQ %d\n", i2c->irq); i2c->state = STATE_IDLE; i2c->dev = &pdev->dev; @@ -605,10 +599,8 @@ static int synquacer_i2c_probe(struct platform_device *pdev) synquacer_i2c_hw_init(i2c); ret = i2c_add_numbered_adapter(&i2c->adapter); - if (ret) { - dev_err(&pdev->dev, "failed to add bus to i2c core\n"); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "failed to add bus to i2c core\n"); platform_set_drvdata(pdev, i2c); -- GitLab From 3d71f43f8a59a62c6ab832d4e73a69bae22e13b7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 3 Aug 2023 14:52:19 +0800 Subject: [PATCH 1002/3445] soundwire: intel_auxdevice: enable pm_runtime earlier on startup As soon as the bus starts, physical peripheral devices may report as ATTACHED and set their status with pm_runtime_set_active() in their update_status()/io_init(). This is problematic with the existing code, since the parent pm_runtime status is changed to "active" after starting the bus. This creates a time window where the pm_runtime framework can report an issue, e.g. "rt711 sdw:0:025d:0711:00: runtime PM trying to activate child device sdw:0:025d:0711:00 but parent (sdw-master-0) is not active" This patch enables runtime_pm earlier to make sure the auxiliary device is pm_runtime active after powering-up, but before starting the bus. This problem was exposed by recent changes in the timing of the bus reset, but was present in this driver since we introduced pm_runtime support. Closes: https://github.com/thesofproject/linux/issues/4328 Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Signed-off-by: Bard Liao Tested-by: Charles Keepax Link: https://lore.kernel.org/r/20230803065220.3823269-2-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel_auxdevice.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/soundwire/intel_auxdevice.c b/drivers/soundwire/intel_auxdevice.c index 0daa6ca9a224e..f51c776eeeffc 100644 --- a/drivers/soundwire/intel_auxdevice.c +++ b/drivers/soundwire/intel_auxdevice.c @@ -248,13 +248,6 @@ int intel_link_startup(struct auxiliary_device *auxdev) sdw_intel_debugfs_init(sdw); - /* start bus */ - ret = sdw_intel_start_bus(sdw); - if (ret) { - dev_err(dev, "bus start failed: %d\n", ret); - goto err_power_up; - } - /* Enable runtime PM */ if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME)) { pm_runtime_set_autosuspend_delay(dev, @@ -266,6 +259,13 @@ int intel_link_startup(struct auxiliary_device *auxdev) pm_runtime_enable(dev); } + /* start bus */ + ret = sdw_intel_start_bus(sdw); + if (ret) { + dev_err(dev, "bus start failed: %d\n", ret); + goto err_pm_runtime; + } + clock_stop_quirks = sdw->link_res->clock_stop_quirks; if (clock_stop_quirks & SDW_INTEL_CLK_STOP_NOT_ALLOWED) { /* @@ -293,12 +293,17 @@ int intel_link_startup(struct auxiliary_device *auxdev) * with a delay. A more complete solution would require the * definition of Master properties. */ - if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME_IDLE)) + if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME_IDLE)) { + pm_runtime_mark_last_busy(dev); pm_runtime_idle(dev); + } sdw->startup_done = true; return 0; +err_pm_runtime: + if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME)) + pm_runtime_disable(dev); err_power_up: sdw_intel_link_power_down(sdw); err_init: -- GitLab From f9031288110589c8f565683a182f194110338d65 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 3 Aug 2023 14:52:20 +0800 Subject: [PATCH 1003/3445] soundWire: intel_auxdevice: resume 'sdw-master' on startup and system resume The SoundWire bus is handled with a dedicated device, which is placed between the Intel auxiliary device and peripheral devices, e.g. soundwire_intel.link.0/sdw-master-0/sdw:0:025d:0711:01 The functionality of this 'sdw-master' device is limited, specifically for pm_runtime the ASoC framework will not rely on pm_runtime_get_sync() since it does not register any components. It will only change status thanks to the parent-child relationship which guarantees that the 'sdw-master' device will be pm_runtime resumed before any peripheral device. However on startup and system resume it's possible that only the auxiliary device is pm_runtime active, and the peripheral will only become active during its io_init routine, leading to another occurrence of the error reported by the pm_runtime framework: rt711 sdw:0:025d:0711:00: runtime PM trying to activate child device sdw:0:025d:0711:00 but parent (sdw-master-0) is not active This patch suggests aligning the sdw-master device status to that of the auxiliary device. The difference between the two is completely notional and their pm_status shouldn't be different during the startup and system resume steps. This problem was exposed by recent changes in the timing of the bus reset, but was present in this driver since we introduced pm_runtime support. Closes: https://github.com/thesofproject/linux/issues/4328 Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Rander Wang Signed-off-by: Bard Liao Tested-by: Charles Keepax Link: https://lore.kernel.org/r/20230803065220.3823269-3-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel_auxdevice.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/soundwire/intel_auxdevice.c b/drivers/soundwire/intel_auxdevice.c index f51c776eeeffc..91c86b46a5a18 100644 --- a/drivers/soundwire/intel_auxdevice.c +++ b/drivers/soundwire/intel_auxdevice.c @@ -257,6 +257,8 @@ int intel_link_startup(struct auxiliary_device *auxdev) pm_runtime_set_active(dev); pm_runtime_enable(dev); + + pm_runtime_resume(bus->dev); } /* start bus */ @@ -294,6 +296,7 @@ int intel_link_startup(struct auxiliary_device *auxdev) * definition of Master properties. */ if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME_IDLE)) { + pm_runtime_mark_last_busy(bus->dev); pm_runtime_mark_last_busy(dev); pm_runtime_idle(dev); } @@ -557,6 +560,8 @@ static int __maybe_unused intel_resume(struct device *dev) pm_runtime_mark_last_busy(dev); pm_runtime_enable(dev); + pm_runtime_resume(bus->dev); + link_flags = md_flags >> (bus->link_id * 8); if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME_IDLE)) @@ -592,6 +597,7 @@ static int __maybe_unused intel_resume(struct device *dev) * counters and delay the pm_runtime suspend by several * seconds, by when all enumeration should be complete. */ + pm_runtime_mark_last_busy(bus->dev); pm_runtime_mark_last_busy(dev); return 0; -- GitLab From 23afc82fb22bccd3f1d2a856d3eccb70453f33b0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 17:13:31 +0800 Subject: [PATCH 1004/3445] soundwire: extend parameters of new_peripheral_assigned() callback The parameters are only the bus and the device number, manager ops may need additional details on the type of peripheral connected, such as whether it is wake-capable or not. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20230731091333.3593132-2-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 2 +- drivers/soundwire/intel_auxdevice.c | 4 +++- include/linux/soundwire/sdw.h | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index dba920ec88f6f..bdd0fed45a8d1 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -781,7 +781,7 @@ static int sdw_assign_device_num(struct sdw_slave *slave) slave->dev_num = slave->dev_num_sticky; if (bus->ops && bus->ops->new_peripheral_assigned) - bus->ops->new_peripheral_assigned(bus, dev_num); + bus->ops->new_peripheral_assigned(bus, slave, dev_num); return 0; } diff --git a/drivers/soundwire/intel_auxdevice.c b/drivers/soundwire/intel_auxdevice.c index 91c86b46a5a18..3e7ca4a4964ae 100644 --- a/drivers/soundwire/intel_auxdevice.c +++ b/drivers/soundwire/intel_auxdevice.c @@ -60,7 +60,9 @@ static int generic_post_bank_switch(struct sdw_bus *bus) return sdw->link_res->hw_ops->post_bank_switch(sdw); } -static void generic_new_peripheral_assigned(struct sdw_bus *bus, int dev_num) +static void generic_new_peripheral_assigned(struct sdw_bus *bus, + struct sdw_slave *slave, + int dev_num) { struct sdw_cdns *cdns = bus_to_cdns(bus); struct sdw_intel *sdw = cdns_to_intel(cdns); diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index f523ceabd0596..94676a3fd0b5d 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -862,7 +862,9 @@ struct sdw_master_ops { int (*pre_bank_switch)(struct sdw_bus *bus); int (*post_bank_switch)(struct sdw_bus *bus); u32 (*read_ping_status)(struct sdw_bus *bus); - void (*new_peripheral_assigned)(struct sdw_bus *bus, int dev_num); + void (*new_peripheral_assigned)(struct sdw_bus *bus, + struct sdw_slave *slave, + int dev_num); }; /** -- GitLab From 39d80b0e5fed2c32f66093fead626358b7106974 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 17:13:32 +0800 Subject: [PATCH 1005/3445] soundwire: bus: add callbacks for device_number allocation Rather than add logic in the core for vendor-specific usages, add callbacks for vendor-specific device_number allocation and release. This patch only moves the existing IDA-based allocator used only by Intel to the intel_auxdevice.c file and does not change the functionality. Follow-up patches will extend the behavior by modifying the Intel callbacks. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20230731091333.3593132-3-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 16 +++++++--------- drivers/soundwire/intel_auxdevice.c | 17 ++++++++++++++++- include/linux/soundwire/sdw.h | 8 ++++---- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index bdd0fed45a8d1..0e1e4bedc708e 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -12,7 +12,6 @@ #include "sysfs_local.h" static DEFINE_IDA(sdw_bus_ida); -static DEFINE_IDA(sdw_peripheral_ida); static int sdw_get_id(struct sdw_bus *bus) { @@ -168,8 +167,8 @@ static int sdw_delete_slave(struct device *dev, void *data) if (slave->dev_num) { /* clear dev_num if assigned */ clear_bit(slave->dev_num, bus->assigned); - if (bus->dev_num_ida_min) - ida_free(&sdw_peripheral_ida, slave->dev_num); + if (bus->ops && bus->ops->put_device_num) + bus->ops->put_device_num(bus, slave); } list_del_init(&slave->node); mutex_unlock(&bus->bus_lock); @@ -710,16 +709,15 @@ EXPORT_SYMBOL(sdw_compare_devid); /* called with bus_lock held */ static int sdw_get_device_num(struct sdw_slave *slave) { + struct sdw_bus *bus = slave->bus; int bit; - if (slave->bus->dev_num_ida_min) { - bit = ida_alloc_range(&sdw_peripheral_ida, - slave->bus->dev_num_ida_min, SDW_MAX_DEVICES, - GFP_KERNEL); + if (bus->ops && bus->ops->get_device_num) { + bit = bus->ops->get_device_num(bus, slave); if (bit < 0) goto err; } else { - bit = find_first_zero_bit(slave->bus->assigned, SDW_MAX_DEVICES); + bit = find_first_zero_bit(bus->assigned, SDW_MAX_DEVICES); if (bit == SDW_MAX_DEVICES) { bit = -ENODEV; goto err; @@ -730,7 +728,7 @@ static int sdw_get_device_num(struct sdw_slave *slave) * Do not update dev_num in Slave data structure here, * Update once program dev_num is successful */ - set_bit(bit, slave->bus->assigned); + set_bit(bit, bus->assigned); err: return bit; diff --git a/drivers/soundwire/intel_auxdevice.c b/drivers/soundwire/intel_auxdevice.c index 3e7ca4a4964ae..65cb3e7b7d251 100644 --- a/drivers/soundwire/intel_auxdevice.c +++ b/drivers/soundwire/intel_auxdevice.c @@ -125,6 +125,20 @@ static int intel_prop_read(struct sdw_bus *bus) return 0; } +static DEFINE_IDA(intel_peripheral_ida); + +static int intel_get_device_num_ida(struct sdw_bus *bus, struct sdw_slave *slave) +{ + return ida_alloc_range(&intel_peripheral_ida, + INTEL_DEV_NUM_IDA_MIN, SDW_MAX_DEVICES, + GFP_KERNEL); +} + +static void intel_put_device_num_ida(struct sdw_bus *bus, struct sdw_slave *slave) +{ + return ida_free(&intel_peripheral_ida, slave->dev_num); +} + static struct sdw_master_ops sdw_intel_ops = { .read_prop = intel_prop_read, .override_adr = sdw_dmi_override_adr, @@ -134,6 +148,8 @@ static struct sdw_master_ops sdw_intel_ops = { .pre_bank_switch = generic_pre_bank_switch, .post_bank_switch = generic_post_bank_switch, .read_ping_status = cdns_read_ping_status, + .get_device_num = intel_get_device_num_ida, + .put_device_num = intel_put_device_num_ida, .new_peripheral_assigned = generic_new_peripheral_assigned, }; @@ -167,7 +183,6 @@ static int intel_link_probe(struct auxiliary_device *auxdev, cdns->msg_count = 0; bus->link_id = auxdev->id; - bus->dev_num_ida_min = INTEL_DEV_NUM_IDA_MIN; bus->clk_stop_timeout = 1; sdw_cdns_probe(cdns); diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 94676a3fd0b5d..bde93ca6aaa6b 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -847,6 +847,8 @@ struct sdw_defer { * @post_bank_switch: Callback for post bank switch * @read_ping_status: Read status from PING frames, reported with two bits per Device. * Bits 31:24 are reserved. + * @get_device_num: Callback for vendor-specific device_number allocation + * @put_device_num: Callback for vendor-specific device_number release * @new_peripheral_assigned: Callback to handle enumeration of new peripheral. */ struct sdw_master_ops { @@ -862,6 +864,8 @@ struct sdw_master_ops { int (*pre_bank_switch)(struct sdw_bus *bus); int (*post_bank_switch)(struct sdw_bus *bus); u32 (*read_ping_status)(struct sdw_bus *bus); + int (*get_device_num)(struct sdw_bus *bus, struct sdw_slave *slave); + void (*put_device_num)(struct sdw_bus *bus, struct sdw_slave *slave); void (*new_peripheral_assigned)(struct sdw_bus *bus, struct sdw_slave *slave, int dev_num); @@ -898,9 +902,6 @@ struct sdw_master_ops { * meaningful if multi_link is set. If set to 1, hardware-based * synchronization will be used even if a stream only uses a single * SoundWire segment. - * @dev_num_ida_min: if set, defines the minimum values for the IDA - * used to allocate system-unique device numbers. This value needs to be - * identical across all SoundWire bus in the system. */ struct sdw_bus { struct device *dev; @@ -927,7 +928,6 @@ struct sdw_bus { u32 bank_switch_timeout; bool multi_link; int hw_sync_min_links; - int dev_num_ida_min; }; int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, -- GitLab From e66f91a2d10b9a25eedcaddee9d6f08c8132760a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 31 Jul 2023 17:13:33 +0800 Subject: [PATCH 1006/3445] soundwire: intel_auxdevice: add hybrid IDA-based device_number allocation The IDA-based allocation is useful to simplify debug, but it was also introduced as a prerequisite to deal with the Intel Lunar Lake hardware programming sequences: the wake-ups have to be handled with a system-unique SDI address at the HDaudio controller level. At the time, the restriction introduced by the IDA to 8 devices total seemed perfectly fine, but recently hardware vendors created configurations with more than 8 devices. Add a new allocation strategy to allow for more than 8 devices using information on the type of devices, and only use the IDA-based allocation for devices capable of generating a wake. In theory the information on wake capabilities should come from firmware, but none of the existing ACPI tables provide it. The drivers set the 'wake_capable' property, but this cannot be used reliably: if the driver probe happens *after* the enumeration, then that property is not initialized yet. Trying to modify the device_number on-the-fly proved to be an impossible task generating race conditions left and right. The only reliable work-around to control the enumeration is to add a quirk table. It's ugly but until platform firmware improves, hopefully as a result of MIPI/SDCA stardization, we can expect that quirk table to grow for each new headset or microphone codec. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20230731091333.3593132-4-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel_auxdevice.c | 72 +++++++++++++++++++++++++---- include/linux/soundwire/sdw_intel.h | 7 +++ 2 files changed, 69 insertions(+), 10 deletions(-) diff --git a/drivers/soundwire/intel_auxdevice.c b/drivers/soundwire/intel_auxdevice.c index 65cb3e7b7d251..7f15e3549e539 100644 --- a/drivers/soundwire/intel_auxdevice.c +++ b/drivers/soundwire/intel_auxdevice.c @@ -23,9 +23,6 @@ #include "intel.h" #include "intel_auxdevice.h" -/* IDA min selected to avoid conflicts with HDaudio/iDISP SDI values */ -#define INTEL_DEV_NUM_IDA_MIN 4 - #define INTEL_MASTER_SUSPEND_DELAY_MS 3000 /* @@ -44,6 +41,39 @@ static int md_flags; module_param_named(sdw_md_flags, md_flags, int, 0444); MODULE_PARM_DESC(sdw_md_flags, "SoundWire Intel Master device flags (0x0 all off)"); +struct wake_capable_part { + const u16 mfg_id; + const u16 part_id; +}; + +static struct wake_capable_part wake_capable_list[] = { + {0x025d, 0x5682}, + {0x025d, 0x700}, + {0x025d, 0x711}, + {0x025d, 0x1712}, + {0x025d, 0x1713}, + {0x025d, 0x1716}, + {0x025d, 0x1717}, + {0x025d, 0x712}, + {0x025d, 0x713}, + {0x025d, 0x714}, + {0x025d, 0x715}, + {0x025d, 0x716}, + {0x025d, 0x717}, + {0x025d, 0x722}, +}; + +static bool is_wake_capable(struct sdw_slave *slave) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(wake_capable_list); i++) + if (slave->id.part_id == wake_capable_list[i].part_id && + slave->id.mfg_id == wake_capable_list[i].mfg_id) + return true; + return false; +} + static int generic_pre_bank_switch(struct sdw_bus *bus) { struct sdw_cdns *cdns = bus_to_cdns(bus); @@ -66,14 +96,26 @@ static void generic_new_peripheral_assigned(struct sdw_bus *bus, { struct sdw_cdns *cdns = bus_to_cdns(bus); struct sdw_intel *sdw = cdns_to_intel(cdns); + int dev_num_min; + int dev_num_max; + bool wake_capable = slave->prop.wake_capable || is_wake_capable(slave); + + if (wake_capable) { + dev_num_min = SDW_INTEL_DEV_NUM_IDA_MIN; + dev_num_max = SDW_MAX_DEVICES; + } else { + dev_num_min = 1; + dev_num_max = SDW_INTEL_DEV_NUM_IDA_MIN - 1; + } /* paranoia check, this should never happen */ - if (dev_num < INTEL_DEV_NUM_IDA_MIN || dev_num > SDW_MAX_DEVICES) { - dev_err(bus->dev, "%s: invalid dev_num %d\n", __func__, dev_num); + if (dev_num < dev_num_min || dev_num > dev_num_max) { + dev_err(bus->dev, "%s: invalid dev_num %d, wake supported %d\n", + __func__, dev_num, slave->prop.wake_capable); return; } - if (sdw->link_res->hw_ops->program_sdi) + if (sdw->link_res->hw_ops->program_sdi && wake_capable) sdw->link_res->hw_ops->program_sdi(sdw, dev_num); } @@ -129,14 +171,24 @@ static DEFINE_IDA(intel_peripheral_ida); static int intel_get_device_num_ida(struct sdw_bus *bus, struct sdw_slave *slave) { - return ida_alloc_range(&intel_peripheral_ida, - INTEL_DEV_NUM_IDA_MIN, SDW_MAX_DEVICES, - GFP_KERNEL); + int bit; + + if (slave->prop.wake_capable || is_wake_capable(slave)) + return ida_alloc_range(&intel_peripheral_ida, + SDW_INTEL_DEV_NUM_IDA_MIN, SDW_MAX_DEVICES, + GFP_KERNEL); + + bit = find_first_zero_bit(slave->bus->assigned, SDW_MAX_DEVICES); + if (bit == SDW_MAX_DEVICES) + return -ENODEV; + + return bit; } static void intel_put_device_num_ida(struct sdw_bus *bus, struct sdw_slave *slave) { - return ida_free(&intel_peripheral_ida, slave->dev_num); + if (slave->prop.wake_capable || is_wake_capable(slave)) + ida_free(&intel_peripheral_ida, slave->dev_num); } static struct sdw_master_ops sdw_intel_ops = { diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h index 11fc88fb0d781..3a824cae7379c 100644 --- a/include/linux/soundwire/sdw_intel.h +++ b/include/linux/soundwire/sdw_intel.h @@ -433,4 +433,11 @@ struct sdw_intel_hw_ops { extern const struct sdw_intel_hw_ops sdw_intel_cnl_hw_ops; extern const struct sdw_intel_hw_ops sdw_intel_lnl_hw_ops; +/* + * IDA min selected to allow for 5 unconstrained devices per link, + * and 6 system-unique Device Numbers for wake-capable devices. + */ + +#define SDW_INTEL_DEV_NUM_IDA_MIN 6 + #endif -- GitLab From b102ce6d847a715732174cfe7119a350f69f3511 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 31 Jul 2023 14:10:09 +0300 Subject: [PATCH 1007/3445] phy: qcom: qmp-ufs: add missing offsets to sm8150 configuration The conversion commit 7559e7572c03 ("phy: Explicitly include correct DT includes") misses offsets configuration for sm8150 (most likely it was developed separately from the series adding HS G4 support and was not adapted for the sm8150/sm8250 configuration split). Add missing offsets to sm8150_ufsphy_cfg. Fixes: 7559e7572c03 ("phy: Explicitly include correct DT includes") Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230731111009.3998089-1-dmitry.baryshkov@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index 03cd47faf3fdd..3927eba8e4684 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -1009,6 +1009,8 @@ static const struct qmp_phy_cfg sm7150_ufsphy_cfg = { static const struct qmp_phy_cfg sm8150_ufsphy_cfg = { .lanes = 2, + .offsets = &qmp_ufs_offsets, + .tbls = { .serdes = sm8150_ufsphy_serdes, .serdes_num = ARRAY_SIZE(sm8150_ufsphy_serdes), -- GitLab From 6ac1bb86953cc8a2419a4845de56c280b6f62890 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Mon, 31 Jul 2023 13:48:56 +0200 Subject: [PATCH 1008/3445] MAINTAINERS: correct file entry in STARFIVE JH7110 DPHY RX DRIVER Commit f8aa660841bc ("phy: starfive: Add mipi dphy rx support") adds the MAINTAINERS section STARFIVE JH7110 DPHY RX DRIVER referring to 'phy-starfive-dphy-rx.c', but the file actually added in this commit is named 'phy-jh7110-dphy-rx.c'. Correct the file entry in STARFIVE JH7110 DPHY RX DRIVER. Signed-off-by: Lukas Bulwahn Reviewed-by: Changhuang Liang Link: https://lore.kernel.org/r/20230731114856.14401-1-lukas.bulwahn@gmail.com Signed-off-by: Vinod Koul --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 0f28f3f8f7008..e6fa4931e373d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20270,7 +20270,7 @@ M: Jack Zhu M: Changhuang Liang S: Supported F: Documentation/devicetree/bindings/phy/starfive,jh7110-dphy-rx.yaml -F: drivers/phy/starfive/phy-starfive-dphy-rx.c +F: drivers/phy/starfive/phy-jh7110-dphy-rx.c STARFIVE JH7110 MMC/SD/SDIO DRIVER M: William Qiu -- GitLab From aff7625322ceaf32c930ebf43c75db442067a88d Mon Sep 17 00:00:00 2001 From: Rohit Agarwal Date: Mon, 7 Aug 2023 19:08:46 +0530 Subject: [PATCH 1009/3445] dt-bindings: phy: qcom,snps-eusb2-repeater: Add compatible for PM7550BA Add a dt-bindings compatible string for the Qualcomm's PM7550BA PMIC. Signed-off-by: Rohit Agarwal Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/1691415534-31820-2-git-send-email-quic_rohiagar@quicinc.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml index 083fda530b484..029569d5fcf35 100644 --- a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-repeater.yaml @@ -15,7 +15,12 @@ description: properties: compatible: - const: qcom,pm8550b-eusb2-repeater + oneOf: + - items: + - enum: + - qcom,pm7550ba-eusb2-repeater + - const: qcom,pm8550b-eusb2-repeater + - const: qcom,pm8550b-eusb2-repeater reg: maxItems: 1 -- GitLab From d35c12b7db15e2c1316c32bad24dea2255c5f7b3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 13:19:55 +0200 Subject: [PATCH 1010/3445] phy: broadcom: sata: fix Wvoid-pointer-to-enum-cast warning 'version' is an enum, thus cast of pointer on 64-bit compile test with W=1 causes: phy-brcm-sata.c:775:19: error: cast to smaller integer type 'enum brcm_sata_phy_version' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810111958.205705-1-krzysztof.kozlowski@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/broadcom/phy-brcm-sata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/broadcom/phy-brcm-sata.c b/drivers/phy/broadcom/phy-brcm-sata.c index 769c707d9b713..ed9e18791ec94 100644 --- a/drivers/phy/broadcom/phy-brcm-sata.c +++ b/drivers/phy/broadcom/phy-brcm-sata.c @@ -772,7 +772,7 @@ static int brcm_sata_phy_probe(struct platform_device *pdev) of_id = of_match_node(brcm_sata_phy_of_match, dn); if (of_id) - priv->version = (enum brcm_sata_phy_version)of_id->data; + priv->version = (uintptr_t)of_id->data; else priv->version = BRCM_SATA_PHY_STB_28NM; -- GitLab From bd6e74a2f0a0c76dda8e44d26f9b91a797586c3b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 13:19:56 +0200 Subject: [PATCH 1011/3445] phy: broadcom: ns-usb3: fix Wvoid-pointer-to-enum-cast warning 'family' is an enum, thus cast of pointer on 64-bit compile test with W=1 causes: drivers/phy/broadcom/phy-bcm-ns-usb3.c:209:17: error: cast to smaller integer type 'enum bcm_ns_family' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810111958.205705-2-krzysztof.kozlowski@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/broadcom/phy-bcm-ns-usb3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/broadcom/phy-bcm-ns-usb3.c b/drivers/phy/broadcom/phy-bcm-ns-usb3.c index bbfad209c890f..69584b685edbb 100644 --- a/drivers/phy/broadcom/phy-bcm-ns-usb3.c +++ b/drivers/phy/broadcom/phy-bcm-ns-usb3.c @@ -206,7 +206,7 @@ static int bcm_ns_usb3_mdio_probe(struct mdio_device *mdiodev) of_id = of_match_device(bcm_ns_usb3_id_table, dev); if (!of_id) return -EINVAL; - usb3->family = (enum bcm_ns_family)of_id->data; + usb3->family = (uintptr_t)of_id->data; syscon_np = of_parse_phandle(dev->of_node, "usb3-dmp-syscon", 0); err = of_address_to_resource(syscon_np, 0, &res); -- GitLab From 2bc00b9b9001329792b14ce20141f334b6debcbc Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 13:19:57 +0200 Subject: [PATCH 1012/3445] phy: broadcom: sr-usb: fix Wvoid-pointer-to-enum-cast warning 'version' is an enum, thus cast of pointer on 64-bit compile test with W=1 causes: phy-bcm-sr-usb.c:314:13: error: cast to smaller integer type 'enum bcm_usb_phy_version' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810111958.205705-3-krzysztof.kozlowski@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/broadcom/phy-bcm-sr-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/broadcom/phy-bcm-sr-usb.c b/drivers/phy/broadcom/phy-bcm-sr-usb.c index 0002da3b5b5d7..b0bd18a5df879 100644 --- a/drivers/phy/broadcom/phy-bcm-sr-usb.c +++ b/drivers/phy/broadcom/phy-bcm-sr-usb.c @@ -311,7 +311,7 @@ static int bcm_usb_phy_probe(struct platform_device *pdev) of_id = of_match_node(bcm_usb_phy_of_match, dn); if (of_id) - version = (enum bcm_usb_phy_version)of_id->data; + version = (uintptr_t)of_id->data; else return -ENODEV; -- GitLab From 7451eecf1ef8be9911749e927ce5690262cc9197 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 13:19:58 +0200 Subject: [PATCH 1013/3445] phy: marvell pxa-usb: fix Wvoid-pointer-to-enum-cast warning 'version' is an enum, thus cast of pointer on 64-bit compile test with W=1 causes: phy-pxa-usb.c:299:26: error: cast to smaller integer type 'enum pxa_usb_phy_version' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810111958.205705-4-krzysztof.kozlowski@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/marvell/phy-pxa-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/marvell/phy-pxa-usb.c b/drivers/phy/marvell/phy-pxa-usb.c index ffe889893ff4a..6c98eb9608e9c 100644 --- a/drivers/phy/marvell/phy-pxa-usb.c +++ b/drivers/phy/marvell/phy-pxa-usb.c @@ -296,7 +296,7 @@ static int pxa_usb_phy_probe(struct platform_device *pdev) of_id = of_match_node(pxa_usb_phy_of_match, dev->of_node); if (of_id) - pxa_usb_phy->version = (enum pxa_usb_phy_version)of_id->data; + pxa_usb_phy->version = (uintptr_t)of_id->data; else pxa_usb_phy->version = PXA_USB_PHY_MMP2; -- GitLab From b606e2e8eded40cacb0a0f0cd60cb45420e9b555 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 9 Aug 2023 21:20:29 +0200 Subject: [PATCH 1014/3445] dt-bindings: arm-smmu: Fix MSM8998 clocks description MSM8998 was abusingly referencing one of the internal bus clocks, that were recently dropped from Linux (because the original implementation did not make much sense), circumventing the interconnect framework. Fix it by dropping the bus-mm clock (which requires separating 8998 from similar entries) and keeping the rest as-is. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230531-topic-8998_mmssclk-v3-6-ba1b1fd9ee75@linaro.org Signed-off-by: Will Deacon --- .../devicetree/bindings/iommu/arm,smmu.yaml | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml index 3a31a979709b6..cf29ab10501cb 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml @@ -270,6 +270,47 @@ allOf: contains: enum: - qcom,msm8998-smmu-v2 + then: + anyOf: + - properties: + clock-names: + items: + - const: bus + clocks: + items: + - description: bus clock required for downstream bus access and for + the smmu ptw + - properties: + clock-names: + items: + - const: iface + - const: mem + - const: mem_iface + clocks: + items: + - description: interface clock required to access smmu's registers + through the TCU's programming interface. + - description: bus clock required for memory access + - description: bus clock required for GPU memory access + - properties: + clock-names: + items: + - const: iface-mm + - const: iface-smmu + - const: bus-smmu + clocks: + items: + - description: interface clock required to access mnoc's registers + through the TCU's programming interface. + - description: interface clock required to access smmu's registers + through the TCU's programming interface. + - description: bus clock required for the smmu ptw + + - if: + properties: + compatible: + contains: + enum: - qcom,sdm630-smmu-v2 - qcom,sm6375-smmu-v2 then: -- GitLab From ec2ff4d8160f5d6fdf1b5be7a47e3ff29563b0ba Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 10 Aug 2023 19:45:04 +0200 Subject: [PATCH 1015/3445] iommu/arm-smmu-qcom: Sort the compatible list alphabetically It got broken at some point, fix it up. Reviewed-by: Dmitry Baryshkov Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230810-topic-lost_smmu_compats-v1-1-64a0d8749404@linaro.org Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c index c71afda79d644..3800ab478216a 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c @@ -251,10 +251,10 @@ static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = { { .compatible = "qcom,sc7280-mss-pil" }, { .compatible = "qcom,sc8180x-mdss" }, { .compatible = "qcom,sc8280xp-mdss" }, - { .compatible = "qcom,sm8150-mdss" }, - { .compatible = "qcom,sm8250-mdss" }, { .compatible = "qcom,sdm845-mdss" }, { .compatible = "qcom,sdm845-mss-pil" }, + { .compatible = "qcom,sm8150-mdss" }, + { .compatible = "qcom,sm8250-mdss" }, { } }; -- GitLab From 6ebaa77ce483effb3e21a22bf534517e12af8c39 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 10 Aug 2023 19:45:05 +0200 Subject: [PATCH 1016/3445] iommu/arm-smmu-qcom: Add SM6375 DPU compatible Add the SM6375 DPU compatible to clients compatible list, as it also needs the workarounds. Acked-by: Dmitry Baryshkov Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230810-topic-lost_smmu_compats-v1-2-64a0d8749404@linaro.org Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c index 3800ab478216a..cc574928c7075 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c @@ -253,6 +253,7 @@ static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = { { .compatible = "qcom,sc8280xp-mdss" }, { .compatible = "qcom,sdm845-mdss" }, { .compatible = "qcom,sdm845-mss-pil" }, + { .compatible = "qcom,sm6375-mdss" }, { .compatible = "qcom,sm8150-mdss" }, { .compatible = "qcom,sm8250-mdss" }, { } -- GitLab From 7e85676a4523c096ec02ff1abcd1a6dd52604002 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 10 Aug 2023 19:45:06 +0200 Subject: [PATCH 1017/3445] iommu/arm-smmu-qcom: Add SM6350 DPU compatible Add the SM6350 DPU compatible to clients compatible list, as it also needs the workarounds. Signed-off-by: Konrad Dybcio Acked-by: Dmitry Baryshkov Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230810-topic-lost_smmu_compats-v1-3-64a0d8749404@linaro.org Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c index cc574928c7075..bdeb587552c02 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c @@ -253,6 +253,7 @@ static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = { { .compatible = "qcom,sc8280xp-mdss" }, { .compatible = "qcom,sdm845-mdss" }, { .compatible = "qcom,sdm845-mss-pil" }, + { .compatible = "qcom,sm6350-mdss" }, { .compatible = "qcom,sm6375-mdss" }, { .compatible = "qcom,sm8150-mdss" }, { .compatible = "qcom,sm8250-mdss" }, -- GitLab From 757d591d965f5fc1cc9888ab480988b6ec8e58fa Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 10 Aug 2023 19:45:07 +0200 Subject: [PATCH 1018/3445] iommu/arm-smmu-qcom: Add SM6375 SMMUv2 SM6375 uses a qcom,smmu-v2-style SMMU just for Adreno and friends. Add a compatible for it. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230810-topic-lost_smmu_compats-v1-4-64a0d8749404@linaro.org Signed-off-by: Will Deacon --- drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c index bdeb587552c02..7f52ac67495fd 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c @@ -530,6 +530,7 @@ static const struct of_device_id __maybe_unused qcom_smmu_impl_of_match[] = { { .compatible = "qcom,sm6125-smmu-500", .data = &qcom_smmu_500_impl0_data }, { .compatible = "qcom,sm6350-smmu-v2", .data = &qcom_smmu_v2_data }, { .compatible = "qcom,sm6350-smmu-500", .data = &qcom_smmu_500_impl0_data }, + { .compatible = "qcom,sm6375-smmu-v2", .data = &qcom_smmu_v2_data }, { .compatible = "qcom,sm6375-smmu-500", .data = &qcom_smmu_500_impl0_data }, { .compatible = "qcom,sm8150-smmu-500", .data = &qcom_smmu_500_impl0_data }, { .compatible = "qcom,sm8250-smmu-500", .data = &qcom_smmu_500_impl0_data }, -- GitLab From 878460e8d0ff84a0edbaff9d06f9d9dbe8353800 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 10 Aug 2023 11:46:20 -0300 Subject: [PATCH 1019/3445] perf build: Remove -Wno-unused-but-set-variable from the flex flags when building with clang < 13.0.0 clang < 13.0.0 doesn't grok -Wno-unused-but-set-variable, so just remove it to avoid: error: unknown warning option '-Wno-unused-but-set-variable'; did you mean '-Wno-unused-const-variable'? [-Werror,-Wunknown-warning-option] make[4]: *** [/git/perf-6.5.0-rc4/tools/build/Makefile.build:128: /tmp/build/perf/util/pmu-flex.o] Error 1 make[4]: *** Waiting for unfinished jobs.... Fixes: ddc8e4c966923ad1 ("perf build: Disable fewer bison warnings") Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/ZNUSWr52jUnVaaa%2F@kernel.org/ Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/Build | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/Build b/tools/perf/util/Build index d487aec0b458a..9699e31ff4c04 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -1,3 +1,4 @@ +include $(srctree)/tools/scripts/Makefile.include include $(srctree)/tools/scripts/utilities.mak perf-y += arm64-frame-pointer-unwind-support.o @@ -301,16 +302,21 @@ else flex_flags := -w endif -CFLAGS_parse-events-flex.o += $(flex_flags) -CFLAGS_pmu-flex.o += $(flex_flags) -CFLAGS_expr-flex.o += $(flex_flags) -CFLAGS_bpf-filter-flex.o += $(flex_flags) - # Some newer clang and gcc version complain about this # util/parse-events-bison.c:1317:9: error: variable 'parse_events_nerrs' set but not used [-Werror,-Wunused-but-set-variable] # int yynerrs = 0; bison_flags := -DYYENABLE_NLS=0 -Wno-unused-but-set-variable + +# Old clangs don't grok -Wno-unused-but-set-variable, remove it +ifeq ($(CC_NO_CLANG), 0) + CLANG_VERSION := $(shell $(CLANG) --version | head -1 | sed 's/.*clang version \([[:digit:]]\+.[[:digit:]]\+.[[:digit:]]\+\).*/\1/g') + ifeq ($(call version-lt3,$(CLANG_VERSION),13.0.0),1) + bison_flags := $(subst -Wno-unused-but-set-variable,,$(bison_flags)) + flex_flags := $(subst -Wno-unused-but-set-variable,,$(flex_flags)) + endif +endif + BISON_GE_382 := $(shell expr $(shell $(BISON) --version | grep bison | sed -e 's/.\+ \([0-9]\+\).\([0-9]\+\).\([0-9]\+\)/\1\2\3/g') \>\= 382) ifeq ($(BISON_GE_382),1) bison_flags += -Wno-switch-enum @@ -323,6 +329,11 @@ ifeq ($(BISON_LT_381),1) bison_flags += -DYYNOMEM=YYABORT endif +CFLAGS_parse-events-flex.o += $(flex_flags) +CFLAGS_pmu-flex.o += $(flex_flags) +CFLAGS_expr-flex.o += $(flex_flags) +CFLAGS_bpf-filter-flex.o += $(flex_flags) + CFLAGS_parse-events-bison.o += $(bison_flags) CFLAGS_pmu-bison.o += -DYYLTYPE_IS_TRIVIAL=0 $(bison_flags) CFLAGS_expr-bison.o += -DYYLTYPE_IS_TRIVIAL=0 $(bison_flags) -- GitLab From e59fea47f83e8a9ac5b772d140a0d67d50ba0ed8 Mon Sep 17 00:00:00 2001 From: Athira Rajeev Date: Fri, 11 Aug 2023 10:45:46 +0530 Subject: [PATCH 1020/3445] perf symbols: Fix DSO kernel load and symbol process to correctly map DSO to its long_name, type and adjust_symbols Test "object code reading" fails sometimes for kernel address as below: Reading object code for memory address: 0xc000000000004c3c File is: [kernel.kallsyms] On file address is: 0x14c3c dso__data_read_offset failed test child finished with -1 ---- end ---- Object code reading: FAILED! Here dso__data_read_offset() fails for symbol address 0xc000000000004c3c. This is because the DSO long_name here is "[kernel.kallsyms]" and hence open_dso() fails to open this file. There is an incorrect DSO to map handling here. The key points here are: - The DSO long_name is set to "[kernel.kallsyms]". This file is not present and hence returns error - The DSO binary type is set to DSO_BINARY_TYPE__NOT_FOUND - The DSO adjust_symbols member is set to zero In the end dso__data_read_offset() returns -1 and the address 0x14c3c can not be resolved. Hence the test fails. But the address actually maps to the kernel DSO # objdump -z -d --start-address=0xc000000000004c3c --stop-address=0xc000000000004cbc /home/athira/linux/vmlinux /home/athira/linux/vmlinux: file format elf64-powerpcle Disassembly of section .head.text: c000000000004c3c : c000000000004c3c: a6 02 9b 7d mfsrr1 r12 c000000000004c40: 78 13 42 7c mr r2,r2 c000000000004c44: 18 00 4d e9 ld r10,24(r13) c000000000004c48: 60 c6 4a 61 ori r10,r10,50784 c000000000004c4c: a6 03 49 7d mtctr r10 Fix dso__process_kernel_symbol() to set the binary_type and adjust_symbols members. dso->adjust_symbols is used by map__rip_2objdump() which converts the symbol start address to the objdump address. Also set dso->long_name in dso__load_vmlinux(). Suggested-by: Adrian Hunter Signed-off-by: Athira Rajeev Acked-by: Adrian Hunter Cc: Disha Goel Cc: Ian Rogers Cc: Jiri Olsa Cc: Kajol Jain Cc: Madhavan Srinivasan Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20230811051546.70039-1-atrajeev@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol-elf.c | 2 ++ tools/perf/util/symbol.c | 15 ++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 8bd466d1c2bdb..95e99c332d7e3 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -1440,6 +1440,8 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, curr_dso->kernel = dso->kernel; curr_dso->long_name = dso->long_name; curr_dso->long_name_len = dso->long_name_len; + curr_dso->binary_type = dso->binary_type; + curr_dso->adjust_symbols = dso->adjust_symbols; curr_map = map__new2(start, curr_dso); dso__put(curr_dso); if (curr_map == NULL) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index f849f9ef68e6c..3f36675b7c8ff 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -2204,15 +2204,20 @@ int dso__load_vmlinux(struct dso *dso, struct map *map, if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type)) return -1; + /* + * dso__load_sym() may copy 'dso' which will result in the copies having + * an incorrect long name unless we set it here first. + */ + dso__set_long_name(dso, vmlinux, vmlinux_allocated); + if (dso->kernel == DSO_SPACE__KERNEL_GUEST) + dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX; + else + dso->binary_type = DSO_BINARY_TYPE__VMLINUX; + err = dso__load_sym(dso, map, &ss, &ss, 0); symsrc__destroy(&ss); if (err > 0) { - if (dso->kernel == DSO_SPACE__KERNEL_GUEST) - dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX; - else - dso->binary_type = DSO_BINARY_TYPE__VMLINUX; - dso__set_long_name(dso, vmlinux, vmlinux_allocated); dso__set_loaded(dso); pr_debug("Using %s for symbols\n", symfs_vmlinux); } -- GitLab From 33d9c5062113a4bd9c5f7414fdeccea3c58e6809 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 10 Aug 2023 11:09:44 -0700 Subject: [PATCH 1021/3445] perf script python: Add stub for PMU symbol to the python binding Fix missing symbol seen in: ``` 19: 'import perf' in python : --- start --- test child forked, pid 2640936 python usage test: "echo "import sys ; sys.path.insert(0, 'python'); import perf" | '/usr/bin/python3' " Traceback (most recent call last): File "", line 1, in ImportError: tools/perf/python/perf.cpython-311-x86_64-linux-gnu.so: undefined symbol: perf_pmus__supports_extended_type test child finished with -1 ---- end ---- 'import perf' in python: FAILED! ``` Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Yang Jihong Link: https://lore.kernel.org/r/20230810180944.2794188-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/python.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 4eed8ec239948..c29f5f0bb552c 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -113,6 +113,11 @@ bool evsel__is_aux_event(const struct evsel *evsel __maybe_unused) return false; } +bool perf_pmus__supports_extended_type(void) +{ + return false; +} + /* * Add this one here not to drag util/metricgroup.c */ -- GitLab From 232ba1630c666b37a5045781e6513cba607fb0d5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 11 Aug 2023 09:01:17 +0200 Subject: [PATCH 1022/3445] openrisc: Make pfn accessors statics inlines Making virt_to_pfn() a static inline taking a strongly typed (const void *) makes the contract of a passing a pointer of that type to the function explicit and exposes any misuse of the macro virt_to_pfn() acting polymorphic and accepting many types such as (void *), (unitptr_t) or (unsigned long) as arguments without warnings. For symmetry, do the same with pfn_to_virt(). Signed-off-by: Linus Walleij Signed-off-by: Stafford Horne --- arch/openrisc/include/asm/page.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/openrisc/include/asm/page.h b/arch/openrisc/include/asm/page.h index 52b0d7e764461..44fc1fd567172 100644 --- a/arch/openrisc/include/asm/page.h +++ b/arch/openrisc/include/asm/page.h @@ -72,8 +72,15 @@ typedef struct page *pgtable_t; #define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET)) #define __pa(x) ((unsigned long) (x) - PAGE_OFFSET) -#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) -#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) +static inline unsigned long virt_to_pfn(const void *kaddr) +{ + return __pa(kaddr) >> PAGE_SHIFT; +} + +static inline void * pfn_to_virt(unsigned long pfn) +{ + return (void *)((unsigned long)__va(pfn) << PAGE_SHIFT); +} #define virt_to_page(addr) \ (mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT)) -- GitLab From 4f74fb30ea21d8b2d515f5929d2b46ad6834edba Mon Sep 17 00:00:00 2001 From: Mitchell Levy Date: Mon, 7 Aug 2023 23:55:47 +0000 Subject: [PATCH 1023/3445] hv_balloon: Update the balloon driver to use the SBRM API This patch is intended as a proof-of-concept for the new SBRM machinery[1]. For some brief background, the idea behind SBRM is using the __cleanup__ attribute to automatically unlock locks (or otherwise release resources) when they go out of scope, similar to C++ style RAII. This promises some benefits such as making code simpler (particularly where you have lots of goto fail; type constructs) as well as reducing the surface area for certain kinds of bugs. The changes in this patch should not result in any difference in how the code actually runs (i.e., it's purely an exercise in this new syntax sugar). In one instance SBRM was not appropriate, so I left that part alone, but all other locking/unlocking is handled automatically in this patch. [1] https://lore.kernel.org/all/20230626125726.GU4253@hirez.programming.kicks-ass.net/ Suggested-by: Boqun Feng Signed-off-by: "Mitchell Levy (Microsoft)" Reviewed-by: Boqun Feng Signed-off-by: Wei Liu Link: https://lore.kernel.org/r/20230807-sbrm-hyperv-v2-1-9d2ac15305bd@gmail.com --- drivers/hv/hv_balloon.c | 82 +++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 44 deletions(-) diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index dffcc894f1173..2812601e84dad 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -8,6 +8,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include @@ -646,7 +647,7 @@ static int hv_memory_notifier(struct notifier_block *nb, unsigned long val, void *v) { struct memory_notify *mem = (struct memory_notify *)v; - unsigned long flags, pfn_count; + unsigned long pfn_count; switch (val) { case MEM_ONLINE: @@ -655,21 +656,22 @@ static int hv_memory_notifier(struct notifier_block *nb, unsigned long val, break; case MEM_OFFLINE: - spin_lock_irqsave(&dm_device.ha_lock, flags); - pfn_count = hv_page_offline_check(mem->start_pfn, - mem->nr_pages); - if (pfn_count <= dm_device.num_pages_onlined) { - dm_device.num_pages_onlined -= pfn_count; - } else { - /* - * We're offlining more pages than we managed to online. - * This is unexpected. In any case don't let - * num_pages_onlined wrap around zero. - */ - WARN_ON_ONCE(1); - dm_device.num_pages_onlined = 0; + scoped_guard(spinlock_irqsave, &dm_device.ha_lock) { + pfn_count = hv_page_offline_check(mem->start_pfn, + mem->nr_pages); + if (pfn_count <= dm_device.num_pages_onlined) { + dm_device.num_pages_onlined -= pfn_count; + } else { + /* + * We're offlining more pages than we + * managed to online. This is + * unexpected. In any case don't let + * num_pages_onlined wrap around zero. + */ + WARN_ON_ONCE(1); + dm_device.num_pages_onlined = 0; + } } - spin_unlock_irqrestore(&dm_device.ha_lock, flags); break; case MEM_GOING_ONLINE: case MEM_GOING_OFFLINE: @@ -721,24 +723,23 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size, unsigned long start_pfn; unsigned long processed_pfn; unsigned long total_pfn = pfn_count; - unsigned long flags; for (i = 0; i < (size/HA_CHUNK); i++) { start_pfn = start + (i * HA_CHUNK); - spin_lock_irqsave(&dm_device.ha_lock, flags); - has->ha_end_pfn += HA_CHUNK; + scoped_guard(spinlock_irqsave, &dm_device.ha_lock) { + has->ha_end_pfn += HA_CHUNK; - if (total_pfn > HA_CHUNK) { - processed_pfn = HA_CHUNK; - total_pfn -= HA_CHUNK; - } else { - processed_pfn = total_pfn; - total_pfn = 0; - } + if (total_pfn > HA_CHUNK) { + processed_pfn = HA_CHUNK; + total_pfn -= HA_CHUNK; + } else { + processed_pfn = total_pfn; + total_pfn = 0; + } - has->covered_end_pfn += processed_pfn; - spin_unlock_irqrestore(&dm_device.ha_lock, flags); + has->covered_end_pfn += processed_pfn; + } reinit_completion(&dm_device.ol_waitevent); @@ -758,10 +759,10 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size, */ do_hot_add = false; } - spin_lock_irqsave(&dm_device.ha_lock, flags); - has->ha_end_pfn -= HA_CHUNK; - has->covered_end_pfn -= processed_pfn; - spin_unlock_irqrestore(&dm_device.ha_lock, flags); + scoped_guard(spinlock_irqsave, &dm_device.ha_lock) { + has->ha_end_pfn -= HA_CHUNK; + has->covered_end_pfn -= processed_pfn; + } break; } @@ -781,10 +782,9 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size, static void hv_online_page(struct page *pg, unsigned int order) { struct hv_hotadd_state *has; - unsigned long flags; unsigned long pfn = page_to_pfn(pg); - spin_lock_irqsave(&dm_device.ha_lock, flags); + guard(spinlock_irqsave)(&dm_device.ha_lock); list_for_each_entry(has, &dm_device.ha_region_list, list) { /* The page belongs to a different HAS. */ if ((pfn < has->start_pfn) || @@ -794,7 +794,6 @@ static void hv_online_page(struct page *pg, unsigned int order) hv_bring_pgs_online(has, pfn, 1UL << order); break; } - spin_unlock_irqrestore(&dm_device.ha_lock, flags); } static int pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt) @@ -803,9 +802,8 @@ static int pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt) struct hv_hotadd_gap *gap; unsigned long residual, new_inc; int ret = 0; - unsigned long flags; - spin_lock_irqsave(&dm_device.ha_lock, flags); + guard(spinlock_irqsave)(&dm_device.ha_lock); list_for_each_entry(has, &dm_device.ha_region_list, list) { /* * If the pfn range we are dealing with is not in the current @@ -852,7 +850,6 @@ static int pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt) ret = 1; break; } - spin_unlock_irqrestore(&dm_device.ha_lock, flags); return ret; } @@ -947,7 +944,6 @@ static unsigned long process_hot_add(unsigned long pg_start, { struct hv_hotadd_state *ha_region = NULL; int covered; - unsigned long flags; if (pfn_cnt == 0) return 0; @@ -979,9 +975,9 @@ static unsigned long process_hot_add(unsigned long pg_start, ha_region->covered_end_pfn = pg_start; ha_region->end_pfn = rg_start + rg_size; - spin_lock_irqsave(&dm_device.ha_lock, flags); - list_add_tail(&ha_region->list, &dm_device.ha_region_list); - spin_unlock_irqrestore(&dm_device.ha_lock, flags); + scoped_guard(spinlock_irqsave, &dm_device.ha_lock) { + list_add_tail(&ha_region->list, &dm_device.ha_region_list); + } } do_pg_range: @@ -2047,7 +2043,6 @@ static void balloon_remove(struct hv_device *dev) struct hv_dynmem_device *dm = hv_get_drvdata(dev); struct hv_hotadd_state *has, *tmp; struct hv_hotadd_gap *gap, *tmp_gap; - unsigned long flags; if (dm->num_pages_ballooned != 0) pr_warn("Ballooned pages: %d\n", dm->num_pages_ballooned); @@ -2073,7 +2068,7 @@ static void balloon_remove(struct hv_device *dev) #endif } - spin_lock_irqsave(&dm_device.ha_lock, flags); + guard(spinlock_irqsave)(&dm_device.ha_lock); list_for_each_entry_safe(has, tmp, &dm->ha_region_list, list) { list_for_each_entry_safe(gap, tmp_gap, &has->gap_list, list) { list_del(&gap->list); @@ -2082,7 +2077,6 @@ static void balloon_remove(struct hv_device *dev) list_del(&has->list); kfree(has); } - spin_unlock_irqrestore(&dm_device.ha_lock, flags); } static int balloon_suspend(struct hv_device *hv_dev) -- GitLab From 25944c068139f6eabc1418458479c30c2f6b2f10 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Mon, 31 Jul 2023 17:21:06 +0800 Subject: [PATCH 1024/3445] RDMA/cxgb4: Set sq_sig_type correctly Replace '0' with IB_SIGNAL_REQ_WR given the sq_sig_type is either IB_SIGNAL_ALL_WR or IB_SIGNAL_REQ_WR per the below. enum ib_sig_type { IB_SIGNAL_ALL_WR, IB_SIGNAL_REQ_WR }; Signed-off-by: Guoqing Jiang Link: https://lore.kernel.org/r/20230731092106.10396-1-guoqing.jiang@linux.dev Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/cxgb4/qp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index ffbd9a89981e7..d16d8eaa14150 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -2466,7 +2466,7 @@ int c4iw_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, init_attr->cap.max_send_sge = qhp->attr.sq_max_sges; init_attr->cap.max_recv_sge = qhp->attr.rq_max_sges; init_attr->cap.max_inline_data = T4_MAX_SEND_INLINE; - init_attr->sq_sig_type = qhp->sq_sig_all ? IB_SIGNAL_ALL_WR : 0; + init_attr->sq_sig_type = qhp->sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR; return 0; } -- GitLab From 40cc695d63352137c832170b125293ef043d4db7 Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Wed, 9 Aug 2023 22:27:18 +0800 Subject: [PATCH 1025/3445] RDMA Remove unused function declarations Commit c2261dd76b54 ("RDMA/device: Add ib_device_set_netdev() as an alternative to get_netdev") declared but never implemented ib_device_netdev(), remove it. Commit 922a8e9fb2e0 ("RDMA: iWARP Connection Manager.") declared but never implemented iw_cm_unbind_qp() and iw_cm_get_qp(). Signed-off-by: Yue Haibing Link: https://lore.kernel.org/r/20230809142718.42316-1-yuehaibing@huawei.com Signed-off-by: Leon Romanovsky --- include/rdma/ib_verbs.h | 2 -- include/rdma/iw_cm.h | 21 --------------------- 2 files changed, 23 deletions(-) diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 1e7774ac808f0..533ab92684d81 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -4440,8 +4440,6 @@ struct net_device *ib_get_net_dev_by_params(struct ib_device *dev, u32 port, const struct sockaddr *addr); int ib_device_set_netdev(struct ib_device *ib_dev, struct net_device *ndev, unsigned int port); -struct net_device *ib_device_netdev(struct ib_device *dev, u32 port); - struct ib_wq *ib_create_wq(struct ib_pd *pd, struct ib_wq_init_attr *init_attr); int ib_destroy_wq_user(struct ib_wq *wq, struct ib_udata *udata); diff --git a/include/rdma/iw_cm.h b/include/rdma/iw_cm.h index 03abd30e6c8ca..2b22f153ef636 100644 --- a/include/rdma/iw_cm.h +++ b/include/rdma/iw_cm.h @@ -114,27 +114,6 @@ struct iw_cm_id *iw_create_cm_id(struct ib_device *device, */ void iw_destroy_cm_id(struct iw_cm_id *cm_id); -/** - * iw_cm_bind_qp - Unbind the specified IW CM identifier and QP - * - * @cm_id: The IW CM idenfier to unbind from the QP. - * @qp: The QP - * - * This is called by the provider when destroying the QP to ensure - * that any references held by the IWCM are released. It may also - * be called by the IWCM when destroying a CM_ID to that any - * references held by the provider are released. - */ -void iw_cm_unbind_qp(struct iw_cm_id *cm_id, struct ib_qp *qp); - -/** - * iw_cm_get_qp - Return the ib_qp associated with a QPN - * - * @ib_device: The IB device - * @qpn: The queue pair number - */ -struct ib_qp *iw_cm_get_qp(struct ib_device *device, int qpn); - /** * iw_cm_listen - Listen for incoming connection requests on the * specified IW CM id. -- GitLab From ca60fd116c7ee1a4471a8ad0fe07cdfa57f24c11 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Wed, 2 Aug 2023 02:00:23 -0700 Subject: [PATCH 1026/3445] IB/core: Add more speed parsing in ib_get_width_and_speed() When the Ethernet driver does not provide the number of lanes in the __ethtool_get_link_ksettings() response, the function ib_get_width_and_speed() does not take consideration of 50G, 100G and 200G speeds while calculating the IB width and speed. Update the width and speed for the above netdev speeds. Signed-off-by: Kalesh AP Signed-off-by: Selvin Xavier Link: https://lore.kernel.org/r/1690966823-8159-1-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/core/verbs.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 25367bd6dd974..41ff5595c8606 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -1899,9 +1899,18 @@ static void ib_get_width_and_speed(u32 netdev_speed, u32 lanes, } else if (netdev_speed <= SPEED_40000) { *width = IB_WIDTH_4X; *speed = IB_SPEED_FDR10; - } else { + } else if (netdev_speed <= SPEED_50000) { + *width = IB_WIDTH_2X; + *speed = IB_SPEED_EDR; + } else if (netdev_speed <= SPEED_100000) { *width = IB_WIDTH_4X; *speed = IB_SPEED_EDR; + } else if (netdev_speed <= SPEED_200000) { + *width = IB_WIDTH_4X; + *speed = IB_SPEED_HDR; + } else { + *width = IB_WIDTH_4X; + *speed = IB_SPEED_NDR; } return; -- GitLab From 1ba67cd3281e50a965c5b519f946b14a1c4620a7 Mon Sep 17 00:00:00 2001 From: Jesse Taube Date: Tue, 8 Aug 2023 20:42:20 -0400 Subject: [PATCH 1027/3445] kconfig: nconf: Add search jump feature Menuconfig has a feature where you can "press the key in the (#) prefix to jump directly to that location. You will be returned to the current search results after exiting this new menu." This commit adds this feature to nconfig, with almost identical code. Signed-off-by: Jesse Taube Acked-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: Masahiro Yamada --- scripts/kconfig/nconf.c | 113 ++++++++++++++++++++++++++++++++---- scripts/kconfig/nconf.gui.c | 37 ++++++++++-- scripts/kconfig/nconf.h | 5 ++ 3 files changed, 140 insertions(+), 15 deletions(-) diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index 3ba8b1af390fd..143a2c351d576 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -220,7 +220,7 @@ search_help[] = "Location:\n" " -> Bus options (PCI, PCMCIA, EISA, ISA)\n" " -> PCI support (PCI [ = y])\n" -" -> PCI access mode ( [ = y])\n" +"(1) -> PCI access mode ( [ = y])\n" "Selects: LIBCRC32\n" "Selected by: BAR\n" "-----------------------------------------------------------------\n" @@ -231,9 +231,13 @@ search_help[] = "o The 'Depends on:' line lists symbols that need to be defined for\n" " this symbol to be visible and selectable in the menu.\n" "o The 'Location:' lines tell, where in the menu structure this symbol\n" -" is located. A location followed by a [ = y] indicates that this is\n" -" a selectable menu item, and the current value is displayed inside\n" -" brackets.\n" +" is located.\n" +" A location followed by a [ = y] indicates that this is\n" +" a selectable menu item, and the current value is displayed inside\n" +" brackets.\n" +" Press the key in the (#) prefix to jump directly to that\n" +" location. You will be returned to the current search results\n" +" after exiting this new menu.\n" "o The 'Selects:' line tells, what symbol will be automatically selected\n" " if this symbol is selected (y or m).\n" "o The 'Selected by' line tells what symbol has selected this symbol.\n" @@ -275,7 +279,9 @@ static const char *current_instructions = menu_instructions; static char *dialog_input_result; static int dialog_input_result_len; +static int jump_key_char; +static void selected_conf(struct menu *menu, struct menu *active_menu); static void conf(struct menu *menu); static void conf_choice(struct menu *menu); static void conf_string(struct menu *menu); @@ -685,6 +691,57 @@ static int do_exit(void) return 0; } +struct search_data { + struct list_head *head; + struct menu *target; +}; + +static int next_jump_key(int key) +{ + if (key < '1' || key > '9') + return '1'; + + key++; + + if (key > '9') + key = '1'; + + return key; +} + +static int handle_search_keys(int key, size_t start, size_t end, void *_data) +{ + struct search_data *data = _data; + struct jump_key *pos; + int index = 0; + + if (key < '1' || key > '9') + return 0; + + list_for_each_entry(pos, data->head, entries) { + index = next_jump_key(index); + + if (pos->offset < start) + continue; + + if (pos->offset >= end) + break; + + if (key == index) { + data->target = pos->target; + return 1; + } + } + + return 0; +} + +int get_jump_key_char(void) +{ + jump_key_char = next_jump_key(jump_key_char); + + return jump_key_char; +} static void search_conf(void) { @@ -692,7 +749,8 @@ static void search_conf(void) struct gstr res; struct gstr title; char *dialog_input; - int dres; + int dres, vscroll = 0, hscroll = 0; + bool again; title = str_new(); str_printf( &title, "Enter (sub)string or regexp to search for " @@ -721,11 +779,28 @@ again: dialog_input += strlen(CONFIG_); sym_arr = sym_re_search(dialog_input); - res = get_relations_str(sym_arr, NULL); + + do { + LIST_HEAD(head); + struct search_data data = { + .head = &head, + .target = NULL, + }; + jump_key_char = 0; + res = get_relations_str(sym_arr, &head); + dres = show_scroll_win_ext(main_window, + "Search Results", str_get(&res), + &vscroll, &hscroll, + handle_search_keys, &data); + again = false; + if (dres >= '1' && dres <= '9') { + assert(data.target != NULL); + selected_conf(data.target->parent, data.target); + again = true; + } + str_free(&res); + } while (again); free(sym_arr); - show_scroll_win(main_window, - "Search Results", str_get(&res)); - str_free(&res); str_free(&title); } @@ -1062,10 +1137,15 @@ static int do_match(int key, struct match_state *state, int *ans) } static void conf(struct menu *menu) +{ + selected_conf(menu, NULL); +} + +static void selected_conf(struct menu *menu, struct menu *active_menu) { struct menu *submenu = NULL; struct symbol *sym; - int res; + int i, res; int current_index = 0; int last_top_row = 0; struct match_state match_state = { @@ -1081,6 +1161,19 @@ static void conf(struct menu *menu) if (!child_count) break; + if (active_menu != NULL) { + for (i = 0; i < items_num; i++) { + struct mitem *mcur; + + mcur = (struct mitem *) item_userptr(curses_menu_items[i]); + if ((struct menu *) mcur->usrptr == active_menu) { + current_index = i; + break; + } + } + active_menu = NULL; + } + show_menu(menu_get_prompt(menu), menu_instructions, current_index, &last_top_row); keypad((menu_win(curses_menu)), TRUE); diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c index 9aedf40f1dc03..25a7263ef3c8c 100644 --- a/scripts/kconfig/nconf.gui.c +++ b/scripts/kconfig/nconf.gui.c @@ -497,10 +497,17 @@ void refresh_all_windows(WINDOW *main_window) refresh(); } -/* layman's scrollable window... */ void show_scroll_win(WINDOW *main_window, const char *title, const char *text) +{ + (void)show_scroll_win_ext(main_window, title, (char *)text, NULL, NULL, NULL, NULL); +} + +/* layman's scrollable window... */ +int show_scroll_win_ext(WINDOW *main_window, const char *title, char *text, + int *vscroll, int *hscroll, + extra_key_cb_fn extra_key_cb, void *data) { int res; int total_lines = get_line_no(text); @@ -514,6 +521,12 @@ void show_scroll_win(WINDOW *main_window, WINDOW *win; WINDOW *pad; PANEL *panel; + bool done = false; + + if (hscroll) + start_x = *hscroll; + if (vscroll) + start_y = *vscroll; getmaxyx(stdscr, lines, columns); @@ -549,8 +562,7 @@ void show_scroll_win(WINDOW *main_window, panel = new_panel(win); /* handle scrolling */ - do { - + while (!done) { copywin(pad, win, start_y, start_x, 2, 2, text_lines, text_cols, 0); print_in_middle(win, @@ -593,8 +605,18 @@ void show_scroll_win(WINDOW *main_window, case 'l': start_x++; break; + default: + if (extra_key_cb) { + size_t start = (get_line(text, start_y) - text); + size_t end = (get_line(text, start_y + text_lines) - text); + + if (extra_key_cb(res, start, end, data)) { + done = true; + break; + } + } } - if (res == 10 || res == 27 || res == 'q' || + if (res == 0 || res == 10 || res == 27 || res == 'q' || res == KEY_F(F_HELP) || res == KEY_F(F_BACK) || res == KEY_F(F_EXIT)) break; @@ -606,9 +628,14 @@ void show_scroll_win(WINDOW *main_window, start_x = 0; if (start_x >= total_cols-text_cols) start_x = total_cols-text_cols; - } while (res); + } + if (hscroll) + *hscroll = start_x; + if (vscroll) + *vscroll = start_y; del_panel(panel); delwin(win); refresh_all_windows(main_window); + return res; } diff --git a/scripts/kconfig/nconf.h b/scripts/kconfig/nconf.h index 6f925bc74eb3d..ab836d5826648 100644 --- a/scripts/kconfig/nconf.h +++ b/scripts/kconfig/nconf.h @@ -67,6 +67,8 @@ typedef enum { void set_colors(void); +typedef int (*extra_key_cb_fn)(int, size_t, size_t, void *); + /* this changes the windows attributes !!! */ void print_in_middle(WINDOW *win, int y, int width, const char *str, int attrs); int get_line_length(const char *line); @@ -78,6 +80,9 @@ int dialog_inputbox(WINDOW *main_window, const char *title, const char *prompt, const char *init, char **resultp, int *result_len); void refresh_all_windows(WINDOW *main_window); +int show_scroll_win_ext(WINDOW *main_window, const char *title, char *text, + int *vscroll, int *hscroll, + extra_key_cb_fn extra_key_cb, void *data); void show_scroll_win(WINDOW *main_window, const char *title, const char *text); -- GitLab From 45a7371d5be21c174be201b8cde0e91b0357c606 Mon Sep 17 00:00:00 2001 From: Jesse Taube Date: Fri, 4 Aug 2023 23:44:45 -0400 Subject: [PATCH 1028/3445] docs: kbuild: Document search jump feature Menuconfig has a feature where you can "press the key in the (#) prefix to jump directly to that location. You will be returned to the current search results after exiting this new menu." This feature is poorly documented, so add it to the kconfig.rst documentation. Signed-off-by: Jesse Taube Acked-by: Randy Dunlap Signed-off-by: Masahiro Yamada --- Documentation/kbuild/kconfig.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/kbuild/kconfig.rst b/Documentation/kbuild/kconfig.rst index 5967c79c3baa7..463914a7fdec6 100644 --- a/Documentation/kbuild/kconfig.rst +++ b/Documentation/kbuild/kconfig.rst @@ -210,6 +210,10 @@ Searching in menuconfig: first (and in alphabetical order), then come all other symbols, sorted in alphabetical order. + In this menu, pressing the key in the (#) prefix will jump + directly to that location. You will be returned to the current + search results after exiting this new menu. + ---------------------------------------------------------------------- User interface options for 'menuconfig' @@ -262,6 +266,10 @@ Searching in nconfig: F8 (SymSearch) searches the configuration symbols for the given string or regular expression (regex). + In the SymSearch, pressing the key in the (#) prefix will + jump directly to that location. You will be returned to the + current search results after exiting this new menu. + NCONFIG_MODE ------------ This mode shows all sub-menus in one large tree. -- GitLab From 130c3f7e4640a0c5b18c1c8461a1d0e1053119c1 Mon Sep 17 00:00:00 2001 From: Li Zetao Date: Fri, 4 Aug 2023 18:06:17 +0800 Subject: [PATCH 1029/3445] watchdog: menz069_wdt: Remove redundant initialization owner in men_z069_driver The module_mcb_driver() will set "THIS_MODULE" to driver.owner when register a mcb_driver driver, so it is redundant initialization to set driver.owner in men_z069_driver statement. Remove it for clean code. Signed-off-by: Li Zetao Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20230804100617.100251-1-lizetao1@huawei.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- 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 3c98030b9fcd0..c7de30270043d 100644 --- a/drivers/watchdog/menz69_wdt.c +++ b/drivers/watchdog/menz69_wdt.c @@ -153,7 +153,6 @@ MODULE_DEVICE_TABLE(mcb, men_z069_ids); static struct mcb_driver men_z069_driver = { .driver = { .name = "z069-wdt", - .owner = THIS_MODULE, }, .probe = men_z069_probe, .remove = men_z069_remove, -- GitLab From e81e57fe89a20c1ee5e0f0b927ce8fe614118458 Mon Sep 17 00:00:00 2001 From: Bharat Bhushan Date: Thu, 3 Aug 2023 08:55:22 +0530 Subject: [PATCH 1030/3445] dt-bindings: watchdog: marvell GTI system watchdog driver Add binding documentation for the Marvell GTI system watchdog driver. Signed-off-by: Bharat Bhushan Reviewed-by: Krzysztof Kozlowski Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20230803032523.6242-1-bbhushan2@marvell.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- .../watchdog/marvell,cn10624-wdt.yaml | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 Documentation/devicetree/bindings/watchdog/marvell,cn10624-wdt.yaml diff --git a/Documentation/devicetree/bindings/watchdog/marvell,cn10624-wdt.yaml b/Documentation/devicetree/bindings/watchdog/marvell,cn10624-wdt.yaml new file mode 100644 index 0000000000000..1b583f232e53e --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/marvell,cn10624-wdt.yaml @@ -0,0 +1,83 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/watchdog/marvell,cn10624-wdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Marvell Global Timer (GTI) system watchdog + +maintainers: + - Bharat Bhushan + +allOf: + - $ref: watchdog.yaml# + +properties: + compatible: + oneOf: + - enum: + - marvell,cn9670-wdt + - marvell,cn10624-wdt + + - items: + - enum: + - marvell,cn9880-wdt + - marvell,cnf9535-wdt + - const: marvell,cn9670-wdt + + - items: + - enum: + - marvell,cn10308-wdt + - marvell,cnf10518-wdt + - const: marvell,cn10624-wdt + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: refclk + + marvell,wdt-timer-index: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 63 + description: + An SoC have many timers (up to 64), firmware can reserve one or more timer + for some other use case and configures one of the global timer as watchdog + timer. Firmware will update this field with the timer number configured + as watchdog timer. + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + #include + soc { + #address-cells = <2>; + #size-cells = <2>; + + watchdog@802000040000 { + compatible = "marvell,cn9670-wdt"; + reg = <0x00008020 0x00040000 0x00000000 0x00020000>; + interrupts = ; + clocks = <&sclk>; + clock-names = "refclk"; + marvell,wdt-timer-index = <63>; + }; + }; + +... -- GitLab From ef9e7fe2c890f7609b5a667eba282f900434e58d Mon Sep 17 00:00:00 2001 From: Bharat Bhushan Date: Thu, 3 Aug 2023 08:55:23 +0530 Subject: [PATCH 1031/3445] Watchdog: Add marvell GTI watchdog driver This patch add support for Marvell GTI watchdog. Global timer unit (GTI) support hardware watchdog timer. Software programs watchdog timer to generate interrupt on first timeout, second timeout is configured to be ignored and system reboots on third timeout. Signed-off-by: Bharat Bhushan Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20230803032523.6242-2-bbhushan2@marvell.com [groeck: MODULE_LICENSE GPL v2 -> GPL since that is sufficient] Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 13 ++ drivers/watchdog/Makefile | 1 + drivers/watchdog/marvell_gti_wdt.c | 340 +++++++++++++++++++++++++++++ 3 files changed, 354 insertions(+) create mode 100644 drivers/watchdog/marvell_gti_wdt.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index ee97d89dfc11a..a23f7a0168e03 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1797,6 +1797,19 @@ config OCTEON_WDT from the first interrupt, it is then only poked when the device is written. +config MARVELL_GTI_WDT + tristate "Marvell GTI Watchdog driver" + depends on ARCH_THUNDER || (COMPILE_TEST && 64BIT) + default y + select WATCHDOG_CORE + help + Marvell GTI hardware supports watchdog timer. First timeout + works as watchdog pretimeout and installed interrupt handler + will be called on first timeout. Hardware can generate interrupt + to SCP on second timeout but it is not enabled, so second + timeout is ignored. If device poke does not happen then system + will reboot on third timeout. + config BCM2835_WDT tristate "Broadcom BCM2835 hardware watchdog" depends on ARCH_BCM2835 || (OF && COMPILE_TEST) diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 3633f5b982362..7eab9de311cb9 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -98,6 +98,7 @@ obj-$(CONFIG_VISCONTI_WATCHDOG) += visconti_wdt.o 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 # X86 (i386 + ia64 + x86_64) Architecture obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o diff --git a/drivers/watchdog/marvell_gti_wdt.c b/drivers/watchdog/marvell_gti_wdt.c new file mode 100644 index 0000000000000..d7eb8286e11ec --- /dev/null +++ b/drivers/watchdog/marvell_gti_wdt.c @@ -0,0 +1,340 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell GTI Watchdog driver + * + * Copyright (C) 2023 Marvell. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Hardware supports following mode of operation: + * 1) Interrupt Only: + * This will generate the interrupt to arm core whenever timeout happens. + * + * 2) Interrupt + del3t (Interrupt to firmware (SCP processor)). + * This will generate interrupt to arm core on 1st timeout happens + * This will generate interrupt to SCP processor on 2nd timeout happens + * + * 3) Interrupt + Interrupt to SCP processor (called delt3t) + reboot. + * This will generate interrupt to arm core on 1st timeout happens + * Will generate interrupt to SCP processor on 2nd timeout happens, + * if interrupt is configured. + * Reboot on 3rd timeout. + * + * Driver will use hardware in mode-3 above so that system can reboot in case + * a hardware hang. Also h/w is configured not to generate SCP interrupt, so + * effectively 2nd timeout is ignored within hardware. + * + * First timeout is effectively watchdog pretimeout. + */ + +/* GTI CWD Watchdog (GTI_CWD_WDOG) Register */ +#define GTI_CWD_WDOG(reg_offset) (0x8 * (reg_offset)) +#define GTI_CWD_WDOG_MODE_INT_DEL3T_RST 0x3 +#define GTI_CWD_WDOG_MODE_MASK GENMASK_ULL(1, 0) +#define GTI_CWD_WDOG_LEN_SHIFT 4 +#define GTI_CWD_WDOG_LEN_MASK GENMASK_ULL(19, 4) +#define GTI_CWD_WDOG_CNT_SHIFT 20 +#define GTI_CWD_WDOG_CNT_MASK GENMASK_ULL(43, 20) + +/* GTI CWD Watchdog Interrupt (GTI_CWD_INT) Register */ +#define GTI_CWD_INT 0x200 +#define GTI_CWD_INT_PENDING_STATUS(bit) BIT_ULL(bit) + +/* GTI CWD Watchdog Interrupt Enable Clear (GTI_CWD_INT_ENA_CLR) Register */ +#define GTI_CWD_INT_ENA_CLR 0x210 +#define GTI_CWD_INT_ENA_CLR_VAL(bit) BIT_ULL(bit) + +/* GTI CWD Watchdog Interrupt Enable Set (GTI_CWD_INT_ENA_SET) Register */ +#define GTI_CWD_INT_ENA_SET 0x218 +#define GTI_CWD_INT_ENA_SET_VAL(bit) BIT_ULL(bit) + +/* GTI CWD Watchdog Poke (GTI_CWD_POKE) Registers */ +#define GTI_CWD_POKE(reg_offset) (0x10000 + 0x8 * (reg_offset)) +#define GTI_CWD_POKE_VAL 1 + +struct gti_match_data { + u32 gti_num_timers; +}; + +static const struct gti_match_data match_data_octeontx2 = { + .gti_num_timers = 54, +}; + +static const struct gti_match_data match_data_cn10k = { + .gti_num_timers = 64, +}; + +struct gti_wdt_priv { + struct watchdog_device wdev; + void __iomem *base; + u32 clock_freq; + struct clk *sclk; + /* wdt_timer_idx used for timer to be used for system watchdog */ + u32 wdt_timer_idx; + const struct gti_match_data *data; +}; + +static irqreturn_t gti_wdt_interrupt(int irq, void *data) +{ + struct watchdog_device *wdev = data; + struct gti_wdt_priv *priv = watchdog_get_drvdata(wdev); + + /* Clear Interrupt Pending Status */ + writeq(GTI_CWD_INT_PENDING_STATUS(priv->wdt_timer_idx), + priv->base + GTI_CWD_INT); + + watchdog_notify_pretimeout(wdev); + + return IRQ_HANDLED; +} + +static int gti_wdt_ping(struct watchdog_device *wdev) +{ + struct gti_wdt_priv *priv = watchdog_get_drvdata(wdev); + + writeq(GTI_CWD_POKE_VAL, + priv->base + GTI_CWD_POKE(priv->wdt_timer_idx)); + + return 0; +} + +static int gti_wdt_start(struct watchdog_device *wdev) +{ + struct gti_wdt_priv *priv = watchdog_get_drvdata(wdev); + u64 regval; + + if (!wdev->pretimeout) + return -EINVAL; + + set_bit(WDOG_HW_RUNNING, &wdev->status); + + /* Clear any pending interrupt */ + writeq(GTI_CWD_INT_PENDING_STATUS(priv->wdt_timer_idx), + priv->base + GTI_CWD_INT); + + /* Enable Interrupt */ + writeq(GTI_CWD_INT_ENA_SET_VAL(priv->wdt_timer_idx), + priv->base + GTI_CWD_INT_ENA_SET); + + /* Set (Interrupt + SCP interrupt (DEL3T) + core domain reset) Mode */ + regval = readq(priv->base + GTI_CWD_WDOG(priv->wdt_timer_idx)); + regval |= GTI_CWD_WDOG_MODE_INT_DEL3T_RST; + writeq(regval, priv->base + GTI_CWD_WDOG(priv->wdt_timer_idx)); + + return 0; +} + +static int gti_wdt_stop(struct watchdog_device *wdev) +{ + struct gti_wdt_priv *priv = watchdog_get_drvdata(wdev); + u64 regval; + + /* Disable Interrupt */ + writeq(GTI_CWD_INT_ENA_CLR_VAL(priv->wdt_timer_idx), + priv->base + GTI_CWD_INT_ENA_CLR); + + /* Set GTI_CWD_WDOG.Mode = 0 to stop the timer */ + regval = readq(priv->base + GTI_CWD_WDOG(priv->wdt_timer_idx)); + regval &= ~GTI_CWD_WDOG_MODE_MASK; + writeq(regval, priv->base + GTI_CWD_WDOG(priv->wdt_timer_idx)); + + return 0; +} + +static int gti_wdt_settimeout(struct watchdog_device *wdev, + unsigned int timeout) +{ + struct gti_wdt_priv *priv = watchdog_get_drvdata(wdev); + u64 timeout_wdog, regval; + + /* Update new timeout */ + wdev->timeout = timeout; + + /* Pretimeout is 1/3 of timeout */ + wdev->pretimeout = timeout / 3; + + /* Get clock cycles from pretimeout */ + timeout_wdog = (u64)priv->clock_freq * wdev->pretimeout; + + /* Watchdog counts in 1024 cycle steps */ + timeout_wdog = timeout_wdog >> 10; + + /* GTI_CWD_WDOG.CNT: reload counter is 16-bit */ + timeout_wdog = (timeout_wdog + 0xff) >> 8; + if (timeout_wdog >= 0x10000) + timeout_wdog = 0xffff; + + /* + * GTI_CWD_WDOG.LEN is 24bit, lower 8-bits should be zero and + * upper 16-bits are same as GTI_CWD_WDOG.CNT + */ + regval = readq(priv->base + GTI_CWD_WDOG(priv->wdt_timer_idx)); + regval &= GTI_CWD_WDOG_MODE_MASK; + regval |= (timeout_wdog << (GTI_CWD_WDOG_CNT_SHIFT + 8)) | + (timeout_wdog << GTI_CWD_WDOG_LEN_SHIFT); + writeq(regval, priv->base + GTI_CWD_WDOG(priv->wdt_timer_idx)); + + return 0; +} + +static int gti_wdt_set_pretimeout(struct watchdog_device *wdev, + unsigned int timeout) +{ + struct gti_wdt_priv *priv = watchdog_get_drvdata(wdev); + struct watchdog_device *wdog_dev = &priv->wdev; + + /* pretimeout should 1/3 of max_timeout */ + if (timeout * 3 <= wdog_dev->max_timeout) + return gti_wdt_settimeout(wdev, timeout * 3); + + return -EINVAL; +} + +static void gti_clk_disable_unprepare(void *data) +{ + clk_disable_unprepare(data); +} + +static int gti_wdt_get_cntfrq(struct platform_device *pdev, + struct gti_wdt_priv *priv) +{ + int err; + + priv->sclk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(priv->sclk)) + return PTR_ERR(priv->sclk); + + err = devm_add_action_or_reset(&pdev->dev, + gti_clk_disable_unprepare, priv->sclk); + if (err) + return err; + + priv->clock_freq = clk_get_rate(priv->sclk); + if (!priv->clock_freq) + return -EINVAL; + + return 0; +} + +static const struct watchdog_info gti_wdt_ident = { + .identity = "Marvell GTI watchdog", + .options = WDIOF_SETTIMEOUT | WDIOF_PRETIMEOUT | WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE | WDIOF_CARDRESET, +}; + +static const struct watchdog_ops gti_wdt_ops = { + .owner = THIS_MODULE, + .start = gti_wdt_start, + .stop = gti_wdt_stop, + .ping = gti_wdt_ping, + .set_timeout = gti_wdt_settimeout, + .set_pretimeout = gti_wdt_set_pretimeout, +}; + +static int gti_wdt_probe(struct platform_device *pdev) +{ + struct gti_wdt_priv *priv; + struct device *dev = &pdev->dev; + struct watchdog_device *wdog_dev; + u64 max_pretimeout; + u32 wdt_idx; + int irq; + int err; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return dev_err_probe(&pdev->dev, PTR_ERR(priv->base), + "reg property not valid/found\n"); + + err = gti_wdt_get_cntfrq(pdev, priv); + if (err) + return dev_err_probe(&pdev->dev, err, + "GTI clock frequency not valid/found"); + + priv->data = of_device_get_match_data(dev); + + /* default use last timer for watchdog */ + priv->wdt_timer_idx = priv->data->gti_num_timers - 1; + + err = of_property_read_u32(dev->of_node, "marvell,wdt-timer-index", + &wdt_idx); + if (!err) { + if (wdt_idx >= priv->data->gti_num_timers) + return dev_err_probe(&pdev->dev, err, + "GTI wdog timer index not valid"); + + priv->wdt_timer_idx = wdt_idx; + } + + wdog_dev = &priv->wdev; + wdog_dev->info = >i_wdt_ident, + wdog_dev->ops = >i_wdt_ops, + wdog_dev->parent = dev; + /* + * Watchdog counter is 24 bit where lower 8 bits are zeros + * This counter decrements every 1024 clock cycles. + */ + max_pretimeout = (GTI_CWD_WDOG_CNT_MASK >> GTI_CWD_WDOG_CNT_SHIFT); + max_pretimeout &= ~0xFFUL; + max_pretimeout = (max_pretimeout * 1024) / priv->clock_freq; + wdog_dev->pretimeout = max_pretimeout; + + /* Maximum timeout is 3 times the pretimeout */ + wdog_dev->max_timeout = max_pretimeout * 3; + /* Minimum first timeout (pretimeout) is 1, so min_timeout as 3 */ + wdog_dev->min_timeout = 3; + wdog_dev->timeout = wdog_dev->pretimeout; + + watchdog_set_drvdata(wdog_dev, priv); + platform_set_drvdata(pdev, priv); + gti_wdt_settimeout(wdog_dev, wdog_dev->timeout); + watchdog_stop_on_reboot(wdog_dev); + watchdog_stop_on_unregister(wdog_dev); + + err = devm_watchdog_register_device(dev, wdog_dev); + if (err) + return err; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return dev_err_probe(&pdev->dev, irq, "IRQ resource not found\n"); + + err = devm_request_irq(dev, irq, gti_wdt_interrupt, 0, + pdev->name, &priv->wdev); + if (err) + return dev_err_probe(dev, err, "Failed to register interrupt handler\n"); + + dev_info(dev, "Watchdog enabled (timeout=%d sec)\n", wdog_dev->timeout); + return 0; +} + +static const struct of_device_id gti_wdt_of_match[] = { + { .compatible = "marvell,cn9670-wdt", .data = &match_data_octeontx2}, + { .compatible = "marvell,cn10624-wdt", .data = &match_data_cn10k}, + { }, +}; +MODULE_DEVICE_TABLE(of, gti_wdt_of_match); + +static struct platform_driver gti_wdt_driver = { + .driver = { + .name = "gti-wdt", + .of_match_table = gti_wdt_of_match, + }, + .probe = gti_wdt_probe, +}; +module_platform_driver(gti_wdt_driver); + +MODULE_AUTHOR("Bharat Bhushan "); +MODULE_DESCRIPTION("Marvell GTI watchdog driver"); +MODULE_LICENSE("GPL"); -- GitLab From cc85f87a77b8d6124c85c9d71d6956c0248fdf19 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 26 Jul 2023 17:33:00 -0600 Subject: [PATCH 1032/3445] watchdog: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it was merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Reviewed-by: Guenter Roeck Acked-by: Alim Akhtar Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230726233302.3812749-1-robh@kernel.org Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/armada_37xx_wdt.c | 1 - drivers/watchdog/at91rm9200_wdt.c | 3 +-- drivers/watchdog/cpwd.c | 2 +- drivers/watchdog/ftwdt010_wdt.c | 6 ++---- drivers/watchdog/gef_wdt.c | 2 +- drivers/watchdog/imx2_wdt.c | 3 +-- drivers/watchdog/imx7ulp_wdt.c | 1 - drivers/watchdog/lantiq_wdt.c | 3 ++- drivers/watchdog/meson_wdt.c | 4 ++-- drivers/watchdog/mpc8xxx_wdt.c | 4 ++-- drivers/watchdog/mtk_wdt.c | 1 - drivers/watchdog/of_xilinx_wdt.c | 3 +-- drivers/watchdog/pic32-dmt.c | 1 - drivers/watchdog/pic32-wdt.c | 1 - drivers/watchdog/pika_wdt.c | 2 +- drivers/watchdog/qcom-wdt.c | 1 - drivers/watchdog/rave-sp-wdt.c | 2 +- drivers/watchdog/riowd.c | 2 +- drivers/watchdog/rza_wdt.c | 4 ++-- drivers/watchdog/rzg2l_wdt.c | 2 +- drivers/watchdog/s3c2410_wdt.c | 1 - drivers/watchdog/sama5d4_wdt.c | 1 - drivers/watchdog/sbsa_gwdt.c | 3 +-- drivers/watchdog/starfive-wdt.c | 3 ++- drivers/watchdog/stm32_iwdg.c | 1 - drivers/watchdog/sunxi_wdt.c | 1 - drivers/watchdog/xilinx_wwdt.c | 4 ++-- 27 files changed, 24 insertions(+), 38 deletions(-) diff --git a/drivers/watchdog/armada_37xx_wdt.c b/drivers/watchdog/armada_37xx_wdt.c index e58652939f8a9..8133a5d05647c 100644 --- a/drivers/watchdog/armada_37xx_wdt.c +++ b/drivers/watchdog/armada_37xx_wdt.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/at91rm9200_wdt.c b/drivers/watchdog/at91rm9200_wdt.c index d20ec27ba3542..558015f08c7a8 100644 --- a/drivers/watchdog/at91rm9200_wdt.c +++ b/drivers/watchdog/at91rm9200_wdt.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -26,8 +27,6 @@ #include #include #include -#include -#include #define WDT_DEFAULT_TIME 5 /* seconds */ #define WDT_MAX_TIME 256 /* seconds */ diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c index 47250f9b68c7d..901b94d456dbd 100644 --- a/drivers/watchdog/cpwd.c +++ b/drivers/watchdog/cpwd.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/watchdog/ftwdt010_wdt.c b/drivers/watchdog/ftwdt010_wdt.c index 442c5bf63ff4d..28f5af752c105 100644 --- a/drivers/watchdog/ftwdt010_wdt.c +++ b/drivers/watchdog/ftwdt010_wdt.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -221,20 +221,18 @@ static const struct dev_pm_ops ftwdt010_wdt_dev_pm_ops = { ftwdt010_wdt_resume) }; -#ifdef CONFIG_OF static const struct of_device_id ftwdt010_wdt_match[] = { { .compatible = "faraday,ftwdt010" }, { .compatible = "cortina,gemini-watchdog" }, {}, }; MODULE_DEVICE_TABLE(of, ftwdt010_wdt_match); -#endif static struct platform_driver ftwdt010_wdt_driver = { .probe = ftwdt010_wdt_probe, .driver = { .name = "ftwdt010-wdt", - .of_match_table = of_match_ptr(ftwdt010_wdt_match), + .of_match_table = ftwdt010_wdt_match, .pm = &ftwdt010_wdt_dev_pm_ops, }, }; diff --git a/drivers/watchdog/gef_wdt.c b/drivers/watchdog/gef_wdt.c index 97afc907f6596..6a1db1c783fa7 100644 --- a/drivers/watchdog/gef_wdt.c +++ b/drivers/watchdog/gef_wdt.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c index 6fcc3596103cc..1a27665a2f533 100644 --- a/drivers/watchdog/imx2_wdt.c +++ b/drivers/watchdog/imx2_wdt.c @@ -26,8 +26,7 @@ #include #include #include -#include -#include +#include #include #include #include diff --git a/drivers/watchdog/imx7ulp_wdt.c b/drivers/watchdog/imx7ulp_wdt.c index 7ca486794ba7f..c703586c6e5f0 100644 --- a/drivers/watchdog/imx7ulp_wdt.c +++ b/drivers/watchdog/imx7ulp_wdt.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c index 6fab504af88b5..a273b97ebcb4b 100644 --- a/drivers/watchdog/lantiq_wdt.c +++ b/drivers/watchdog/lantiq_wdt.c @@ -9,7 +9,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/drivers/watchdog/meson_wdt.c b/drivers/watchdog/meson_wdt.c index 539feaa1f904d..497496f64f556 100644 --- a/drivers/watchdog/meson_wdt.c +++ b/drivers/watchdog/meson_wdt.c @@ -11,11 +11,11 @@ #include #include #include +#include #include #include -#include -#include #include +#include #include #include diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index 1c569be72ea29..867f9f3113797 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c @@ -16,8 +16,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c index a9c437598e7eb..b2330b16b497a 100644 --- a/drivers/watchdog/mtk_wdt.c +++ b/drivers/watchdog/mtk_wdt.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c index 2a079ca04aa3b..05657dc1d36a0 100644 --- a/drivers/watchdog/of_xilinx_wdt.c +++ b/drivers/watchdog/of_xilinx_wdt.c @@ -10,14 +10,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include -#include /* Register offsets for the Wdt device */ #define XWT_TWCSR0_OFFSET 0x0 /* Control/Status Register0 */ diff --git a/drivers/watchdog/pic32-dmt.c b/drivers/watchdog/pic32-dmt.c index bc4ccddc75a3f..ab0682492c85a 100644 --- a/drivers/watchdog/pic32-dmt.c +++ b/drivers/watchdog/pic32-dmt.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/pic32-wdt.c b/drivers/watchdog/pic32-wdt.c index 6d1a00222991f..1d282de312ef1 100644 --- a/drivers/watchdog/pic32-wdt.c +++ b/drivers/watchdog/pic32-wdt.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/pika_wdt.c b/drivers/watchdog/pika_wdt.c index a98abd0d31467..782b8c23d99cd 100644 --- a/drivers/watchdog/pika_wdt.c +++ b/drivers/watchdog/pika_wdt.c @@ -23,8 +23,8 @@ #include #include #include +#include #include -#include #define DRV_NAME "PIKA-WDT" diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c index d776474dcdf34..9e790f0c2096c 100644 --- a/drivers/watchdog/qcom-wdt.c +++ b/drivers/watchdog/qcom-wdt.c @@ -11,7 +11,6 @@ #include #include #include -#include enum wdt_reg { WDT_RST, diff --git a/drivers/watchdog/rave-sp-wdt.c b/drivers/watchdog/rave-sp-wdt.c index 2c95615b63547..5d1c2176d445d 100644 --- a/drivers/watchdog/rave-sp-wdt.c +++ b/drivers/watchdog/rave-sp-wdt.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/watchdog/riowd.c b/drivers/watchdog/riowd.c index c04b383e1712e..b293792a292a3 100644 --- a/drivers/watchdog/riowd.c +++ b/drivers/watchdog/riowd.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/watchdog/rza_wdt.c b/drivers/watchdog/rza_wdt.c index fe6c2ed35e04c..cb4901b3f7778 100644 --- a/drivers/watchdog/rza_wdt.c +++ b/drivers/watchdog/rza_wdt.c @@ -9,9 +9,9 @@ #include #include #include +#include #include -#include -#include +#include #include #include diff --git a/drivers/watchdog/rzg2l_wdt.c b/drivers/watchdog/rzg2l_wdt.c index d404953d0e0f4..1741f98ca67c5 100644 --- a/drivers/watchdog/rzg2l_wdt.c +++ b/drivers/watchdog/rzg2l_wdt.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 95416a9bdd4b4..2bcc8faa7fa5a 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/sama5d4_wdt.c b/drivers/watchdog/sama5d4_wdt.c index aeee934ca51bf..71e8b5fbf51fe 100644 --- a/drivers/watchdog/sama5d4_wdt.c +++ b/drivers/watchdog/sama5d4_wdt.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c index fd3cfdda49491..421ebcda62e64 100644 --- a/drivers/watchdog/sbsa_gwdt.c +++ b/drivers/watchdog/sbsa_gwdt.c @@ -43,10 +43,9 @@ #include #include #include +#include #include #include -#include -#include #include #include #include diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wdt.c index 8058fca4d05d3..9e6db8e0164f4 100644 --- a/drivers/watchdog/starfive-wdt.c +++ b/drivers/watchdog/starfive-wdt.c @@ -8,7 +8,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c index 570a71509d2a9..fa5e70c4b93a4 100644 --- a/drivers/watchdog/stm32_iwdg.c +++ b/drivers/watchdog/stm32_iwdg.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include diff --git a/drivers/watchdog/sunxi_wdt.c b/drivers/watchdog/sunxi_wdt.c index 6cf82922d3fb5..b85354a995826 100644 --- a/drivers/watchdog/sunxi_wdt.c +++ b/drivers/watchdog/sunxi_wdt.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/xilinx_wwdt.c b/drivers/watchdog/xilinx_wwdt.c index 2585038d55758..1d998db415335 100644 --- a/drivers/watchdog/xilinx_wwdt.c +++ b/drivers/watchdog/xilinx_wwdt.c @@ -9,9 +9,9 @@ #include #include #include +#include #include -#include -#include +#include #include /* Max timeout is calculated at 100MHz source clock */ -- GitLab From 6eb28a38f6478a650c7e76b2d6910669615d8a62 Mon Sep 17 00:00:00 2001 From: Florent CARLI Date: Fri, 21 Jul 2023 10:13:47 +0200 Subject: [PATCH 1033/3445] watchdog: advantech_ec_wdt: fix Kconfig dependencies This driver uses the WATCHDOG_CORE framework and ISA_BUS_API. This commit has these dependencies correctly selected. Signed-off-by: Florent CARLI Co-authored-by: Yoann Congal Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20230721081347.52069-1-fcarli@gmail.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index a23f7a0168e03..5a1d0380c66b4 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1075,6 +1075,8 @@ config ADVANTECH_WDT config ADVANTECH_EC_WDT tristate "Advantech Embedded Controller Watchdog Timer" depends on X86 + select ISA_BUS_API + select WATCHDOG_CORE help This driver supports Advantech products with ITE based Embedded Controller. It does not support Advantech products with other ECs or without EC. -- GitLab From f1a43aadb5a690e141a3b6700e2a40c1d4dbe088 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 28 Jul 2023 13:50:21 -0600 Subject: [PATCH 1034/3445] watchdog: Enable COMPILE_TEST for more drivers There's quite a few watchdog drivers which are easily enabled for COMPILE_TEST, so let's enable them. Signed-off-by: Rob Herring Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20230728195022.1198555-1-robh@kernel.org Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 80 ++++++++++++++++---------------- drivers/watchdog/loongson1_wdt.c | 1 + 2 files changed, 41 insertions(+), 40 deletions(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 5a1d0380c66b4..f5057b35fcfdb 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -307,7 +307,7 @@ config XILINX_WATCHDOG config XILINX_WINDOW_WATCHDOG tristate "Xilinx window watchdog timer" depends on HAS_IOMEM - depends on ARM64 + depends on ARM64 || COMPILE_TEST select WATCHDOG_CORE help Window watchdog driver for the versal_wwdt IP core. @@ -343,7 +343,7 @@ config RAVE_SP_WATCHDOG config MLX_WDT tristate "Mellanox Watchdog" - depends on MELLANOX_PLATFORM + depends on MELLANOX_PLATFORM || COMPILE_TEST select WATCHDOG_CORE select REGMAP help @@ -493,7 +493,7 @@ config FTWDT010_WATCHDOG config IXP4XX_WATCHDOG tristate "IXP4xx Watchdog" - depends on ARCH_IXP4XX + depends on ARCH_IXP4XX || (ARM && COMPILE_TEST) select WATCHDOG_CORE help Say Y here if to include support for the watchdog timer @@ -529,7 +529,7 @@ config S3C2410_WATCHDOG config SA1100_WATCHDOG tristate "SA1100/PXA2xx watchdog" - depends on ARCH_SA1100 || ARCH_PXA + depends on ARCH_SA1100 || ARCH_PXA || COMPILE_TEST help Watchdog timer embedded into SA11x0 and PXA2xx chips. This will reboot your system when timeout is reached. @@ -720,7 +720,7 @@ config IMX2_WDT config IMX_SC_WDT tristate "IMX SC Watchdog" depends on HAVE_ARM_SMCCC - depends on IMX_SCU + depends on IMX_SCU || COMPILE_TEST select WATCHDOG_CORE help This is the driver for the system controller watchdog @@ -931,7 +931,7 @@ config ASPEED_WATCHDOG config STM32_WATCHDOG tristate "STM32 Independent WatchDoG (IWDG) support" - depends on ARCH_STM32 + depends on ARCH_STM32 || COMPILE_TEST select WATCHDOG_CORE default y help @@ -1065,7 +1065,7 @@ config ACQUIRE_WDT config ADVANTECH_WDT tristate "Advantech SBC Watchdog Timer" - depends on X86 + depends on X86 || COMPILE_TEST help If you are configuring a Linux kernel for the Advantech single-board computer, say `Y' here to support its built-in watchdog timer @@ -1074,7 +1074,7 @@ config ADVANTECH_WDT config ADVANTECH_EC_WDT tristate "Advantech Embedded Controller Watchdog Timer" - depends on X86 + depends on X86 || COMPILE_TEST select ISA_BUS_API select WATCHDOG_CORE help @@ -1083,7 +1083,7 @@ config ADVANTECH_EC_WDT config ALIM1535_WDT tristate "ALi M1535 PMU Watchdog Timer" - depends on X86 && PCI + depends on (X86 || COMPILE_TEST) && PCI help This is the driver for the hardware watchdog on the ALi M1535 PMU. @@ -1107,7 +1107,7 @@ config ALIM7101_WDT config EBC_C384_WDT tristate "WinSystems EBC-C384 Watchdog Timer" - depends on X86 + depends on X86 || COMPILE_TEST select ISA_BUS_API select WATCHDOG_CORE help @@ -1117,7 +1117,7 @@ config EBC_C384_WDT config EXAR_WDT tristate "Exar Watchdog Timer" - depends on X86 + depends on X86 || COMPILE_TEST select WATCHDOG_CORE help Enables watchdog timer support for the watchdog timer present @@ -1128,7 +1128,7 @@ config EXAR_WDT config F71808E_WDT tristate "Fintek F718xx, F818xx Super I/O Watchdog" - depends on X86 + depends on X86 || COMPILE_TEST select WATCHDOG_CORE help This is the driver for the hardware watchdog on the Fintek F71808E, @@ -1140,7 +1140,7 @@ config F71808E_WDT config SP5100_TCO tristate "AMD/ATI SP5100 TCO Timer/Watchdog" - depends on X86 && PCI + depends on (X86 || COMPILE_TEST) && PCI select WATCHDOG_CORE help Hardware watchdog driver for the AMD/ATI SP5100 chipset. The TCO @@ -1179,7 +1179,7 @@ config SC520_WDT config SBC_FITPC2_WATCHDOG tristate "Compulab SBC-FITPC2 watchdog" - depends on X86 + depends on X86 || COMPILE_TEST help This is the driver for the built-in watchdog timer on the fit-PC2, fit-PC2i, CM-iAM single-board computers made by Compulab. @@ -1204,7 +1204,7 @@ config SBC_FITPC2_WATCHDOG config EUROTECH_WDT tristate "Eurotech CPU-1220/1410 Watchdog Timer" - depends on X86 + depends on X86 || COMPILE_TEST help Enable support for the watchdog timer on the Eurotech CPU-1220 and CPU-1410 cards. These are PC/104 SBCs. Spec sheets and product @@ -1212,7 +1212,7 @@ config EUROTECH_WDT config IB700_WDT tristate "IB700 SBC Watchdog Timer" - depends on X86 + depends on X86 || COMPILE_TEST help This is the driver for the hardware watchdog on the IB700 Single Board Computer produced by TMC Technology (www.tmc-uk.com). This @@ -1229,7 +1229,7 @@ config IB700_WDT config IBMASR tristate "IBM Automatic Server Restart" - depends on X86 + depends on X86 || COMPILE_TEST help This is the driver for the IBM Automatic Server Restart watchdog timer built-in into some eServer xSeries machines. @@ -1239,7 +1239,7 @@ config IBMASR config WAFER_WDT tristate "ICP Single Board Computer Watchdog Timer" - depends on X86 + depends on X86 || COMPILE_TEST help This is a driver for the hardware watchdog on the ICP Single Board Computer. This driver is working on (at least) the following @@ -1261,7 +1261,7 @@ config I6300ESB_WDT config IE6XX_WDT tristate "Intel Atom E6xx Watchdog" - depends on X86 && PCI + depends on (X86 || COMPILE_TEST) && PCI select WATCHDOG_CORE select MFD_CORE select LPC_SCH @@ -1321,7 +1321,7 @@ config ITCO_VENDOR_SUPPORT config IT8712F_WDT tristate "IT8712F (Smart Guardian) Watchdog Timer" - depends on X86 + depends on X86 || COMPILE_TEST help This is the driver for the built-in watchdog timer on the IT8712F Super I/0 chipset used on many motherboards. @@ -1334,7 +1334,7 @@ config IT8712F_WDT config IT87_WDT tristate "IT87 Watchdog Timer" - depends on X86 + depends on X86 || COMPILE_TEST select WATCHDOG_CORE help This is the driver for the hardware watchdog on the ITE IT8607, @@ -1352,7 +1352,7 @@ config IT87_WDT config HP_WATCHDOG tristate "HP ProLiant iLO2+ Hardware Watchdog Timer" select WATCHDOG_CORE - depends on (ARM64 || X86) && PCI + depends on (ARM64 || X86 || COMPILE_TEST) && PCI help A software monitoring watchdog and NMI handling driver. This driver will detect lockups and provide a stack trace. This is a driver that @@ -1382,7 +1382,7 @@ config KEMPLD_WDT config SC1200_WDT tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog" - depends on X86 + depends on X86 || COMPILE_TEST help This is a driver for National Semiconductor PC87307/PC97307 hardware watchdog cards as found on the SC1200. This watchdog is mainly used @@ -1405,7 +1405,7 @@ config SCx200_WDT config PC87413_WDT tristate "NS PC87413 watchdog" - depends on X86 + depends on X86 || COMPILE_TEST help This is the driver for the hardware watchdog on the PC87413 chipset This watchdog simply watches your kernel to make sure it doesn't @@ -1419,7 +1419,7 @@ config PC87413_WDT config NV_TCO tristate "nVidia TCO Timer/Watchdog" - depends on X86 && PCI + depends on (X86 || COMPILE_TEST) && PCI help Hardware driver for the TCO timer built into the nVidia Hub family (such as the MCP51). The TCO (Total Cost of Ownership) timer is a @@ -1448,7 +1448,7 @@ config RDC321X_WDT config 60XX_WDT tristate "SBC-60XX Watchdog Timer" - depends on X86 + depends on X86 || COMPILE_TEST help This driver can be used with the watchdog timer found on some single board computers, namely the 6010 PII based computer. @@ -1488,7 +1488,7 @@ config SBC7240_WDT config CPU5_WDT tristate "SMA CPU5 Watchdog" - depends on X86 + depends on X86 || COMPILE_TEST help TBD. To compile this driver as a module, choose M here: the @@ -1496,7 +1496,7 @@ config CPU5_WDT config SMSC_SCH311X_WDT tristate "SMSC SCH311X Watchdog Timer" - depends on X86 + depends on X86 || COMPILE_TEST help This is the driver for the hardware watchdog timer on the SMSC SCH3112, SCH3114 and SCH3116 Super IO chipset @@ -1508,7 +1508,7 @@ config SMSC_SCH311X_WDT config SMSC37B787_WDT tristate "Winbond SMsC37B787 Watchdog Timer" - depends on X86 + depends on X86 || COMPILE_TEST help This is the driver for the hardware watchdog component on the Winbond SMsC37B787 chipset as used on the NetRunner Mainboard @@ -1528,7 +1528,7 @@ config SMSC37B787_WDT config TQMX86_WDT tristate "TQ-Systems TQMX86 Watchdog Timer" - depends on X86 + depends on X86 || COMPILE_TEST select WATCHDOG_CORE help This is the driver for the hardware watchdog timer in the TQMX86 IO @@ -1541,7 +1541,7 @@ config TQMX86_WDT config VIA_WDT tristate "VIA Watchdog Timer" - depends on X86 && PCI + depends on (X86 || COMPILE_TEST) && PCI select WATCHDOG_CORE help This is the driver for the hardware watchdog timer on VIA @@ -1554,7 +1554,7 @@ config VIA_WDT config W83627HF_WDT tristate "Watchdog timer for W83627HF/W83627DHG and compatibles" - depends on X86 + depends on X86 || COMPILE_TEST select WATCHDOG_CORE help This is the driver for the hardware watchdog on the following @@ -1584,7 +1584,7 @@ config W83627HF_WDT config W83877F_WDT tristate "W83877F (EMACS) Watchdog Timer" - depends on X86 + depends on X86 || COMPILE_TEST help This is the driver for the hardware watchdog on the W83877F chipset as used in EMACS PC-104 motherboards (and likely others). This @@ -1599,7 +1599,7 @@ config W83877F_WDT config W83977F_WDT tristate "W83977F (PCM-5335) Watchdog Timer" - depends on X86 + depends on X86 || COMPILE_TEST help This is the driver for the hardware watchdog on the W83977F I/O chip as used in AAEON's PCM-5335 SBC (and likely others). This @@ -1612,7 +1612,7 @@ config W83977F_WDT config MACHZ_WDT tristate "ZF MachZ Watchdog" - depends on X86 + depends on X86 || COMPILE_TEST 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 @@ -1625,7 +1625,7 @@ config MACHZ_WDT config SBC_EPX_C3_WATCHDOG tristate "Winsystems SBC EPX-C3 watchdog" - depends on X86 + depends on X86 || COMPILE_TEST help This is the driver for the built-in watchdog timer on the EPX-C3 Single-board computer made by Winsystems, Inc. @@ -1740,7 +1740,7 @@ config INDYDOG config JZ4740_WDT tristate "Ingenic jz4740 SoC hardware watchdog" - depends on MIPS + depends on MIPS || COMPILE_TEST depends on COMMON_CLK select WATCHDOG_CORE select MFD_SYSCON @@ -1837,7 +1837,7 @@ config BCM_KONA_WDT config BCM_KONA_WDT_DEBUG bool "DEBUGFS support for BCM Kona Watchdog" - depends on BCM_KONA_WDT + depends on BCM_KONA_WDT || COMPILE_TEST help If enabled, adds /sys/kernel/debug/bcm_kona_wdt/info which provides access to the driver's internal data structures as well as watchdog @@ -1878,7 +1878,7 @@ config LANTIQ_WDT config LOONGSON1_WDT tristate "Loongson1 SoC hardware watchdog" - depends on MACH_LOONGSON32 + depends on MACH_LOONGSON32 || COMPILE_TEST select WATCHDOG_CORE help Hardware driver for the Loongson1 SoC Watchdog Timer. @@ -1892,7 +1892,7 @@ config RALINK_WDT config GXP_WATCHDOG tristate "HPE GXP watchdog support" - depends on ARCH_HPE_GXP + depends on ARCH_HPE_GXP || COMPILE_TEST select WATCHDOG_CORE help Say Y here to include support for the watchdog timer diff --git a/drivers/watchdog/loongson1_wdt.c b/drivers/watchdog/loongson1_wdt.c index 4ac7810a314d7..0587ff44d3a12 100644 --- a/drivers/watchdog/loongson1_wdt.c +++ b/drivers/watchdog/loongson1_wdt.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include -- GitLab From 254a8ed6aab39c869d99da97f25035ed15756337 Mon Sep 17 00:00:00 2001 From: "GONG, Ruiqi" Date: Fri, 11 Aug 2023 21:32:45 +0800 Subject: [PATCH 1035/3445] tomoyo: remove unused function declaration The last usage of tomoyo_check_flags() has been removed by commit 57c2590fb7fd ("TOMOYO: Update profile structure."). Clean up its residual declaration. Signed-off-by: GONG, Ruiqi Signed-off-by: Tetsuo Handa --- security/tomoyo/common.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index e669837ed0e31..0e8e2e959aef4 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -1037,8 +1037,6 @@ struct tomoyo_policy_namespace *tomoyo_assign_namespace (const char *domainname); struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns, const u8 profile); -unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain, - const u8 index); u8 tomoyo_parse_ulong(unsigned long *result, char **str); void *tomoyo_commit_ok(void *data, const unsigned int size); void __init tomoyo_load_builtin_policy(void); -- GitLab From 4d3696801bad2a037832c15a8d21dfe0c529d9cd Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Sat, 12 Aug 2023 18:23:59 -0700 Subject: [PATCH 1036/3445] ARC: -Wmissing-prototype warning fixes Anrd reported [1] new compiler warnings due to -Wmissing-protype. These are for non static functions mostly used in asm code hence not exported already. Fix this by adding the prototypes. [1] https://lore.kernel.org/lkml/20230810141947.1236730-1-arnd@kernel.org Reviewed-by: Arnd Bergmann Signed-off-by: Vineet Gupta --- arch/arc/include/asm/entry.h | 21 +++++++++++++++++++++ arch/arc/include/asm/irq.h | 1 + arch/arc/include/asm/mmu.h | 2 ++ arch/arc/include/asm/ptrace.h | 3 +++ arch/arc/include/asm/setup.h | 2 ++ arch/arc/include/asm/smp.h | 2 ++ arch/arc/kernel/ctx_sw.c | 2 +- arch/arc/kernel/devtree.c | 1 + arch/arc/kernel/intc-arcv2.c | 2 +- arch/arc/kernel/signal.c | 1 + arch/arc/kernel/smp.c | 7 ++++--- arch/arc/kernel/stacktrace.c | 1 + arch/arc/kernel/traps.c | 1 + arch/arc/mm/cache.c | 8 ++++---- arch/arc/mm/fault.c | 1 + arch/arc/mm/init.c | 1 + arch/arc/mm/tlb.c | 2 +- 17 files changed, 48 insertions(+), 10 deletions(-) diff --git a/arch/arc/include/asm/entry.h b/arch/arc/include/asm/entry.h index fcdd59d77f42c..2980bc9b76531 100644 --- a/arch/arc/include/asm/entry.h +++ b/arch/arc/include/asm/entry.h @@ -13,6 +13,8 @@ #include /* For VMALLOC_START */ #include +#ifdef __ASSEMBLY__ + #ifdef CONFIG_ISA_ARCOMPACT #include /* ISA specific bits */ #else @@ -295,4 +297,23 @@ #endif /* CONFIG_ARC_CURR_IN_REG */ +#else /* !__ASSEMBLY__ */ + +extern void do_signal(struct pt_regs *); +extern void do_notify_resume(struct pt_regs *); +extern int do_privilege_fault(unsigned long, struct pt_regs *); +extern int do_extension_fault(unsigned long, struct pt_regs *); +extern int insterror_is_error(unsigned long, struct pt_regs *); +extern int do_memory_error(unsigned long, struct pt_regs *); +extern int trap_is_brkpt(unsigned long, struct pt_regs *); +extern int do_misaligned_error(unsigned long, struct pt_regs *); +extern int do_trap5_error(unsigned long, struct pt_regs *); +extern int do_misaligned_access(unsigned long, struct pt_regs *, struct callee_regs *); +extern void do_machine_check_fault(unsigned long, struct pt_regs *); +extern void do_non_swi_trap(unsigned long, struct pt_regs *); +extern void do_insterror_or_kprobe(unsigned long, struct pt_regs *); +extern void do_page_fault(unsigned long, struct pt_regs *); + +#endif + #endif /* __ASM_ARC_ENTRY_H */ diff --git a/arch/arc/include/asm/irq.h b/arch/arc/include/asm/irq.h index 0309cb405cfb1..c574712ad8658 100644 --- a/arch/arc/include/asm/irq.h +++ b/arch/arc/include/asm/irq.h @@ -25,5 +25,6 @@ #include extern void arc_init_IRQ(void); +extern void arch_do_IRQ(unsigned int, struct pt_regs *); #endif diff --git a/arch/arc/include/asm/mmu.h b/arch/arc/include/asm/mmu.h index ca427c30f70eb..9febf5bc3de6d 100644 --- a/arch/arc/include/asm/mmu.h +++ b/arch/arc/include/asm/mmu.h @@ -14,6 +14,8 @@ typedef struct { unsigned long asid[NR_CPUS]; /* 8 bit MMU PID + Generation cycle */ } mm_context_t; +extern void do_tlb_overlap_fault(unsigned long, unsigned long, struct pt_regs *); + #endif #include diff --git a/arch/arc/include/asm/ptrace.h b/arch/arc/include/asm/ptrace.h index 5869a74c0db2f..cf90fcd2a6284 100644 --- a/arch/arc/include/asm/ptrace.h +++ b/arch/arc/include/asm/ptrace.h @@ -181,6 +181,9 @@ static inline unsigned long regs_get_register(struct pt_regs *regs, return *(unsigned long *)((unsigned long)regs + offset); } +extern int syscall_trace_entry(struct pt_regs *); +extern void syscall_trace_exit(struct pt_regs *); + #endif /* !__ASSEMBLY__ */ #endif /* __ASM_PTRACE_H */ diff --git a/arch/arc/include/asm/setup.h b/arch/arc/include/asm/setup.h index 028a8cf762069..374138832c5a7 100644 --- a/arch/arc/include/asm/setup.h +++ b/arch/arc/include/asm/setup.h @@ -42,4 +42,6 @@ extern void arc_cache_init(void); extern char *arc_cache_mumbojumbo(int cpu_id, char *buf, int len); extern void read_decode_cache_bcr(void); +extern void __init handle_uboot_args(void); + #endif /* __ASMARC_SETUP_H */ diff --git a/arch/arc/include/asm/smp.h b/arch/arc/include/asm/smp.h index d856491606acd..e0913f52c2cdd 100644 --- a/arch/arc/include/asm/smp.h +++ b/arch/arc/include/asm/smp.h @@ -29,6 +29,8 @@ extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); extern void __init smp_init_cpus(void); extern void first_lines_of_secondary(void); extern const char *arc_platform_smp_cpuinfo(void); +extern void arc_platform_smp_wait_to_boot(int); +extern void start_kernel_secondary(void); /* * API expected BY platform smp code (FROM arch smp code) diff --git a/arch/arc/kernel/ctx_sw.c b/arch/arc/kernel/ctx_sw.c index 1a76f2d6f6943..bf16f777a0bc3 100644 --- a/arch/arc/kernel/ctx_sw.c +++ b/arch/arc/kernel/ctx_sw.c @@ -12,7 +12,7 @@ */ #include -#include +#include #include #define KSP_WORD_OFF ((TASK_THREAD + THREAD_KSP) / 4) diff --git a/arch/arc/kernel/devtree.c b/arch/arc/kernel/devtree.c index 721d465f15809..4c9e61457b2f6 100644 --- a/arch/arc/kernel/devtree.c +++ b/arch/arc/kernel/devtree.c @@ -12,6 +12,7 @@ #include #include #include +#include #ifdef CONFIG_SERIAL_EARLYCON diff --git a/arch/arc/kernel/intc-arcv2.c b/arch/arc/kernel/intc-arcv2.c index 5cda19d0aa913..678898757e473 100644 --- a/arch/arc/kernel/intc-arcv2.c +++ b/arch/arc/kernel/intc-arcv2.c @@ -108,7 +108,7 @@ static void arcv2_irq_unmask(struct irq_data *data) write_aux_reg(AUX_IRQ_ENABLE, 1); } -void arcv2_irq_enable(struct irq_data *data) +static void arcv2_irq_enable(struct irq_data *data) { /* set default priority */ write_aux_reg(AUX_IRQ_SELECT, data->hwirq); diff --git a/arch/arc/kernel/signal.c b/arch/arc/kernel/signal.c index 3c1590c27fae3..0b3bb529d2463 100644 --- a/arch/arc/kernel/signal.c +++ b/arch/arc/kernel/signal.c @@ -53,6 +53,7 @@ #include #include +#include struct rt_sigframe { struct siginfo info; diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c index 409cfa4675b40..8d9b188caa27b 100644 --- a/arch/arc/kernel/smp.c +++ b/arch/arc/kernel/smp.c @@ -23,9 +23,10 @@ #include #include -#include -#include #include +#include +#include +#include #ifndef CONFIG_ARC_HAS_LLSC arch_spinlock_t smp_atomic_ops_lock = __ARCH_SPIN_LOCK_UNLOCKED; @@ -351,7 +352,7 @@ static inline int __do_IPI(unsigned long msg) * arch-common ISR to handle for inter-processor interrupts * Has hooks for platform specific IPI */ -irqreturn_t do_IPI(int irq, void *dev_id) +static irqreturn_t do_IPI(int irq, void *dev_id) { unsigned long pending; unsigned long __maybe_unused copy; diff --git a/arch/arc/kernel/stacktrace.c b/arch/arc/kernel/stacktrace.c index 5372dc04e7847..ea99c066ef250 100644 --- a/arch/arc/kernel/stacktrace.c +++ b/arch/arc/kernel/stacktrace.c @@ -29,6 +29,7 @@ #include #include +#include #include /*------------------------------------------------------------------------- diff --git a/arch/arc/kernel/traps.c b/arch/arc/kernel/traps.c index 6b83e3f2b41c3..2f7eb786695b3 100644 --- a/arch/arc/kernel/traps.c +++ b/arch/arc/kernel/traps.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/arc/mm/cache.c b/arch/arc/mm/cache.c index 55c6de138eae0..bdaa4aa40947d 100644 --- a/arch/arc/mm/cache.c +++ b/arch/arc/mm/cache.c @@ -581,7 +581,7 @@ static void __ic_line_inv_vaddr(phys_addr_t paddr, unsigned long vaddr, #endif /* CONFIG_ARC_HAS_ICACHE */ -noinline void slc_op_rgn(phys_addr_t paddr, unsigned long sz, const int op) +static noinline void slc_op_rgn(phys_addr_t paddr, unsigned long sz, const int op) { #ifdef CONFIG_ISA_ARCV2 /* @@ -644,7 +644,7 @@ noinline void slc_op_rgn(phys_addr_t paddr, unsigned long sz, const int op) #endif } -noinline void slc_op_line(phys_addr_t paddr, unsigned long sz, const int op) +static __maybe_unused noinline void slc_op_line(phys_addr_t paddr, unsigned long sz, const int op) { #ifdef CONFIG_ISA_ARCV2 /* @@ -1069,7 +1069,7 @@ SYSCALL_DEFINE3(cacheflush, uint32_t, start, uint32_t, sz, uint32_t, flags) * 3. All Caches need to be disabled when setting up IOC to elide any in-flight * Coherency transactions */ -noinline void __init arc_ioc_setup(void) +static noinline void __init arc_ioc_setup(void) { unsigned int ioc_base, mem_sz; @@ -1131,7 +1131,7 @@ noinline void __init arc_ioc_setup(void) * one core suffices for all * - IOC setup / dma callbacks only need to be done once */ -void __init arc_cache_init_master(void) +static noinline void __init arc_cache_init_master(void) { unsigned int __maybe_unused cpu = smp_processor_id(); diff --git a/arch/arc/mm/fault.c b/arch/arc/mm/fault.c index f59e722d147f9..26e5823c57106 100644 --- a/arch/arc/mm/fault.c +++ b/arch/arc/mm/fault.c @@ -13,6 +13,7 @@ #include #include #include +#include #include /* diff --git a/arch/arc/mm/init.c b/arch/arc/mm/init.c index 9f64d729c9f87..6a71b23f1383c 100644 --- a/arch/arc/mm/init.c +++ b/arch/arc/mm/init.c @@ -15,6 +15,7 @@ #include #include #include +#include #include pgd_t swapper_pg_dir[PTRS_PER_PGD] __aligned(PAGE_SIZE); diff --git a/arch/arc/mm/tlb.c b/arch/arc/mm/tlb.c index 5f71445f26bde..2a3105a682c31 100644 --- a/arch/arc/mm/tlb.c +++ b/arch/arc/mm/tlb.c @@ -389,7 +389,7 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end) /* * Routine to create a TLB entry */ -void create_tlb(struct vm_area_struct *vma, unsigned long vaddr, pte_t *ptep) +static void create_tlb(struct vm_area_struct *vma, unsigned long vaddr, pte_t *ptep) { unsigned long flags; unsigned int asid_or_sasid, rwx; -- GitLab From 53e9e33ede37a247d926db5e4a9e56b55204e66c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 10 Aug 2023 22:45:32 -0700 Subject: [PATCH 1037/3445] printk: ringbuffer: Fix truncating buffer size min_t cast If an output buffer size exceeded U16_MAX, the min_t(u16, ...) cast in copy_data() was causing writes to truncate. This manifested as output bytes being skipped, seen as %NUL bytes in pstore dumps when the available record size was larger than 65536. Fix the cast to no longer truncate the calculation. Cc: Petr Mladek Cc: Sergey Senozhatsky Cc: Steven Rostedt Cc: John Ogness Reported-by: Vijay Balakrishna Link: https://lore.kernel.org/lkml/d8bb1ec7-a4c5-43a2-9de0-9643a70b899f@linux.microsoft.com/ Fixes: b6cf8b3f3312 ("printk: add lockless ringbuffer") Cc: stable@vger.kernel.org Signed-off-by: Kees Cook Tested-by: Vijay Balakrishna Tested-by: Guilherme G. Piccoli # Steam Deck Reviewed-by: Tyler Hicks (Microsoft) Tested-by: Tyler Hicks (Microsoft) Reviewed-by: John Ogness Reviewed-by: Sergey Senozhatsky Reviewed-by: Petr Mladek Signed-off-by: Petr Mladek Link: https://lore.kernel.org/r/20230811054528.never.165-kees@kernel.org --- kernel/printk/printk_ringbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/printk/printk_ringbuffer.c b/kernel/printk/printk_ringbuffer.c index 2dc4d5a1f1ff8..fde338606ce83 100644 --- a/kernel/printk/printk_ringbuffer.c +++ b/kernel/printk/printk_ringbuffer.c @@ -1735,7 +1735,7 @@ static bool copy_data(struct prb_data_ring *data_ring, if (!buf || !buf_size) return true; - data_size = min_t(u16, buf_size, len); + data_size = min_t(unsigned int, buf_size, len); memcpy(&buf[0], data, data_size); /* LMM(copy_data:A) */ return true; -- GitLab From 3253f6923a7825e301e05130afede82dde62acc9 Mon Sep 17 00:00:00 2001 From: Harry Geyer Date: Thu, 27 Jul 2023 17:22:55 +0100 Subject: [PATCH 1038/3445] i2c: tiny-usb: check usb base class before assuming the interface on device is for this driver Patch allows usb devices with multiple interfaces to use this driver without this driver assuming all interfaces are i2c-tiny-usb. Signed-off-by: Harry Geyer Reviewed-by: Andi Shyti Link: https://lore.kernel.org/r/20230727162255.21551-1-harry.geyer@devtank.co.uk Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tiny-usb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c index d1fa9ff5aeab4..1bffe36c40ad8 100644 --- a/drivers/i2c/busses/i2c-tiny-usb.c +++ b/drivers/i2c/busses/i2c-tiny-usb.c @@ -222,6 +222,10 @@ static int i2c_tiny_usb_probe(struct usb_interface *interface, int retval = -ENOMEM; u16 version; + if (interface->intf_assoc && + interface->intf_assoc->bFunctionClass != USB_CLASS_VENDOR_SPEC) + return -ENODEV; + dev_dbg(&interface->dev, "probing usb device\n"); /* allocate memory for our device state and initialize it */ -- GitLab From 91ec6c85599b60c00caf4e9a9d6c4d6e5dd5e93c Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 14 Aug 2023 13:05:30 +0200 Subject: [PATCH 1039/3445] Revert "fuse: in fuse_flush only wait if someone wants the return code" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 5a8bee63b10f6f2f52f6d22e109a4a147409842a. Jürg Billeter reports the following regression: Since v6.3-rc1 commit 5a8bee63b1 ("fuse: in fuse_flush only wait if someone wants the return code") `fput()` is called asynchronously if a file is closed as part of a process exiting, i.e., if there was no explicit `close()` before exit. If the file was open for writing, also `put_write_access()` is called asynchronously as part of the async `fput()`. If that newly written file is an executable, attempting to `execve()` the new file can fail with `ETXTBSY` if it's called after the writer process exited but before the async `fput()` has run. Reported-and-tested-by: "Jürg Billeter" Cc: # v6.3 Link: https://lore.kernel.org/all/4f66cded234462964899f2a661750d6798a57ec0.camel@bitron.ch/ Signed-off-by: Miklos Szeredi --- fs/fuse/file.c | 89 +++++++++++++++----------------------------------- 1 file changed, 26 insertions(+), 63 deletions(-) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index bc4115288eec7..1c7599ed90625 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -19,7 +19,6 @@ #include #include #include -#include static int fuse_send_open(struct fuse_mount *fm, u64 nodeid, unsigned int open_flags, int opcode, @@ -479,36 +478,48 @@ static void fuse_sync_writes(struct inode *inode) fuse_release_nowrite(inode); } -struct fuse_flush_args { - struct fuse_args args; - struct fuse_flush_in inarg; - struct work_struct work; - struct file *file; -}; - -static int fuse_do_flush(struct fuse_flush_args *fa) +static int fuse_flush(struct file *file, fl_owner_t id) { - int err; - struct inode *inode = file_inode(fa->file); + struct inode *inode = file_inode(file); struct fuse_mount *fm = get_fuse_mount(inode); + struct fuse_file *ff = file->private_data; + struct fuse_flush_in inarg; + FUSE_ARGS(args); + int err; + + if (fuse_is_bad(inode)) + return -EIO; + + if (ff->open_flags & FOPEN_NOFLUSH && !fm->fc->writeback_cache) + return 0; err = write_inode_now(inode, 1); if (err) - goto out; + return err; inode_lock(inode); fuse_sync_writes(inode); inode_unlock(inode); - err = filemap_check_errors(fa->file->f_mapping); + err = filemap_check_errors(file->f_mapping); if (err) - goto out; + return err; err = 0; if (fm->fc->no_flush) goto inval_attr_out; - err = fuse_simple_request(fm, &fa->args); + memset(&inarg, 0, sizeof(inarg)); + inarg.fh = ff->fh; + inarg.lock_owner = fuse_lock_owner_id(fm->fc, id); + args.opcode = FUSE_FLUSH; + args.nodeid = get_node_id(inode); + args.in_numargs = 1; + args.in_args[0].size = sizeof(inarg); + args.in_args[0].value = &inarg; + args.force = true; + + err = fuse_simple_request(fm, &args); if (err == -ENOSYS) { fm->fc->no_flush = 1; err = 0; @@ -521,57 +532,9 @@ inval_attr_out: */ if (!err && fm->fc->writeback_cache) fuse_invalidate_attr_mask(inode, STATX_BLOCKS); - -out: - fput(fa->file); - kfree(fa); return err; } -static void fuse_flush_async(struct work_struct *work) -{ - struct fuse_flush_args *fa = container_of(work, typeof(*fa), work); - - fuse_do_flush(fa); -} - -static int fuse_flush(struct file *file, fl_owner_t id) -{ - struct fuse_flush_args *fa; - struct inode *inode = file_inode(file); - struct fuse_mount *fm = get_fuse_mount(inode); - struct fuse_file *ff = file->private_data; - - if (fuse_is_bad(inode)) - return -EIO; - - if (ff->open_flags & FOPEN_NOFLUSH && !fm->fc->writeback_cache) - return 0; - - fa = kzalloc(sizeof(*fa), GFP_KERNEL); - if (!fa) - return -ENOMEM; - - fa->inarg.fh = ff->fh; - fa->inarg.lock_owner = fuse_lock_owner_id(fm->fc, id); - fa->args.opcode = FUSE_FLUSH; - fa->args.nodeid = get_node_id(inode); - fa->args.in_numargs = 1; - fa->args.in_args[0].size = sizeof(fa->inarg); - fa->args.in_args[0].value = &fa->inarg; - fa->args.force = true; - fa->file = get_file(file); - - /* Don't wait if the task is exiting */ - if (current->flags & PF_EXITING) { - INIT_WORK(&fa->work, fuse_flush_async); - schedule_work(&fa->work); - return 0; - } - - return fuse_do_flush(fa); -} - int fuse_fsync_common(struct file *file, loff_t start, loff_t end, int datasync, int opcode) { -- GitLab From 59738ab26644ecb9bd05378a948c4a6e036e4916 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Jul 2023 11:46:16 -0600 Subject: [PATCH 1040/3445] I2C: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-at91-core.c | 1 - drivers/i2c/busses/i2c-at91-master.c | 1 - drivers/i2c/busses/i2c-bcm-iproc.c | 2 +- drivers/i2c/busses/i2c-bcm2835.c | 2 +- drivers/i2c/busses/i2c-cpm.c | 4 ++-- drivers/i2c/busses/i2c-davinci.c | 2 +- drivers/i2c/busses/i2c-emev2.c | 2 +- drivers/i2c/busses/i2c-exynos5.c | 4 +--- drivers/i2c/busses/i2c-gxp.c | 3 ++- drivers/i2c/busses/i2c-ibm_iic.c | 3 ++- drivers/i2c/busses/i2c-imx-lpi2c.c | 1 - drivers/i2c/busses/i2c-imx.c | 1 - drivers/i2c/busses/i2c-jz4780.c | 2 +- drivers/i2c/busses/i2c-lpc2k.c | 1 - drivers/i2c/busses/i2c-meson.c | 1 - drivers/i2c/busses/i2c-mlxbf.c | 2 +- drivers/i2c/busses/i2c-mpc.c | 3 ++- drivers/i2c/busses/i2c-mt65xx.c | 4 +--- drivers/i2c/busses/i2c-mt7621.c | 3 ++- drivers/i2c/busses/i2c-mxs.c | 1 - drivers/i2c/busses/i2c-npcm7xx.c | 1 - drivers/i2c/busses/i2c-owl.c | 3 ++- drivers/i2c/busses/i2c-pca-platform.c | 1 - drivers/i2c/busses/i2c-pxa-pci.c | 1 - drivers/i2c/busses/i2c-rcar.c | 2 +- drivers/i2c/busses/i2c-riic.c | 1 - drivers/i2c/busses/i2c-s3c2410.c | 1 - drivers/i2c/busses/i2c-sh_mobile.c | 2 +- drivers/i2c/busses/i2c-sprd.c | 1 - drivers/i2c/busses/i2c-tegra-bpmp.c | 2 +- drivers/i2c/busses/i2c-tegra.c | 2 +- drivers/i2c/muxes/i2c-mux-gpmux.c | 2 +- drivers/i2c/muxes/i2c-mux-ltc4306.c | 1 - 33 files changed, 25 insertions(+), 38 deletions(-) diff --git a/drivers/i2c/busses/i2c-at91-core.c b/drivers/i2c/busses/i2c-at91-core.c index 05ad3bc3578ac..3563a7fd75dbd 100644 --- a/drivers/i2c/busses/i2c-at91-core.c +++ b/drivers/i2c/busses/i2c-at91-core.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-at91-master.c b/drivers/i2c/busses/i2c-at91-master.c index c0c35785a0dc4..94cff1cd527e3 100644 --- a/drivers/i2c/busses/i2c-at91-master.c +++ b/drivers/i2c/busses/i2c-at91-master.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index 8a3e2208475c9..66d8bfabfbf58 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index 9af1a68269ab0..b92de19442216 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index 732daf6a932b3..9a664abf734d6 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -26,10 +26,10 @@ #include #include #include +#include #include -#include #include -#include +#include #include #include diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 329c952d50627..02b3b1160fb06 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/i2c/busses/i2c-emev2.c b/drivers/i2c/busses/i2c-emev2.c index 4ba93cd91c0f0..5574094104457 100644 --- a/drivers/i2c/busses/i2c-emev2.c +++ b/drivers/i2c/busses/i2c-emev2.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 5b201a326c13b..2b0b9cdffa861 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -18,9 +18,7 @@ #include #include #include -#include -#include -#include +#include #include /* diff --git a/drivers/i2c/busses/i2c-gxp.c b/drivers/i2c/busses/i2c-gxp.c index 70b0de07ed99a..efafc0528c44d 100644 --- a/drivers/i2c/busses/i2c-gxp.c +++ b/drivers/i2c/busses/i2c-gxp.c @@ -4,8 +4,9 @@ #include #include #include +#include #include -#include +#include #include #include diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 1ad9d3b26dd3f..408820319ec48 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -37,9 +37,10 @@ #include #include #include +#include #include #include -#include +#include #include "i2c-ibm_iic.h" diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index 0af286d934bd5..7c011039940fe 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index c0cac5bcfdd1c..10e89586ca72f 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c index 0dfe603995214..55035cca0ae53 100644 --- a/drivers/i2c/busses/i2c-jz4780.c +++ b/drivers/i2c/busses/i2c-jz4780.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/i2c/busses/i2c-lpc2k.c b/drivers/i2c/busses/i2c-lpc2k.c index c61157f1409b3..e3660333e91cc 100644 --- a/drivers/i2c/busses/i2c-lpc2k.c +++ b/drivers/i2c/busses/i2c-lpc2k.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index 16026c895bb65..c7b203cc44345 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c index 5ee82016c8050..bf2eaeac3e7cd 100644 --- a/drivers/i2c/busses/i2c-mlxbf.c +++ b/drivers/i2c/busses/i2c-mlxbf.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index f460a7fb4eae6..e4e4995ab2243 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -11,9 +11,10 @@ #include #include #include +#include #include #include -#include +#include #include #include diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c index 21cc39e35cf61..1a9b5a068ef1b 100644 --- a/drivers/i2c/busses/i2c-mt65xx.c +++ b/drivers/i2c/busses/i2c-mt65xx.c @@ -19,9 +19,7 @@ #include #include #include -#include -#include -#include +#include #include #include #include diff --git a/drivers/i2c/busses/i2c-mt7621.c b/drivers/i2c/busses/i2c-mt7621.c index 104bb194e9906..81d46169bc1f9 100644 --- a/drivers/i2c/busses/i2c-mt7621.c +++ b/drivers/i2c/busses/i2c-mt7621.c @@ -16,7 +16,8 @@ #include #include #include -#include +#include +#include #include #define REG_SM0CFG2_REG 0x28 diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 1d76f1c4dc06a..36def0a9c95c4 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c index 53b65ffb6a647..495a8b5f6a2ba 100644 --- a/drivers/i2c/busses/i2c-npcm7xx.c +++ b/drivers/i2c/busses/i2c-npcm7xx.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include diff --git a/drivers/i2c/busses/i2c-owl.c b/drivers/i2c/busses/i2c-owl.c index 5f0ef8c351418..777f1a0278c74 100644 --- a/drivers/i2c/busses/i2c-owl.c +++ b/drivers/i2c/busses/i2c-owl.c @@ -16,7 +16,8 @@ #include #include #include -#include +#include +#include /* I2C registers */ #define OWL_I2C_REG_CTL 0x0000 diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c index d2a9e7b61c1ab..b8d5480c54f65 100644 --- a/drivers/i2c/busses/i2c-pca-platform.c +++ b/drivers/i2c/busses/i2c-pca-platform.c @@ -22,7 +22,6 @@ #include #include #include -#include #include diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c index 30e38bc8b6db8..08b3229c443df 100644 --- a/drivers/i2c/busses/i2c-pxa-pci.c +++ b/drivers/i2c/busses/i2c-pxa-pci.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #define CE4100_PCI_I2C_DEVS 3 diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 6b7f0f27d0c3c..a32a93f9a60d0 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index 5f8c0bd508d2f..f0ee8871d5ae1 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 92f0cb4df1795..302c70aadc112 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 324407196a10e..67a991b45076e 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/i2c/busses/i2c-sprd.c b/drivers/i2c/busses/i2c-sprd.c index ffc54fbf814dd..c52d1bec60b4c 100644 --- a/drivers/i2c/busses/i2c-sprd.c +++ b/drivers/i2c/busses/i2c-sprd.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/drivers/i2c/busses/i2c-tegra-bpmp.c b/drivers/i2c/busses/i2c-tegra-bpmp.c index bc3f94561746e..b0840fa0f53e0 100644 --- a/drivers/i2c/busses/i2c-tegra-bpmp.c +++ b/drivers/i2c/busses/i2c-tegra-bpmp.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index bcbbf23aa530c..6851347f3b9f1 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/i2c/muxes/i2c-mux-gpmux.c b/drivers/i2c/muxes/i2c-mux-gpmux.c index 0405af0e15104..baccf4bfaf028 100644 --- a/drivers/i2c/muxes/i2c-mux-gpmux.c +++ b/drivers/i2c/muxes/i2c-mux-gpmux.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include struct mux { diff --git a/drivers/i2c/muxes/i2c-mux-ltc4306.c b/drivers/i2c/muxes/i2c-mux-ltc4306.c index 637e25506490d..23766d853e767 100644 --- a/drivers/i2c/muxes/i2c-mux-ltc4306.c +++ b/drivers/i2c/muxes/i2c-mux-ltc4306.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include -- GitLab From 0a310eef70c0a9d9c956e1b532c9505e6952d1b0 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 14:33:40 +0800 Subject: [PATCH 1041/3445] i2c: at91: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-at91-core.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-at91-core.c b/drivers/i2c/busses/i2c-at91-core.c index 3563a7fd75dbd..91d66ec145884 100644 --- a/drivers/i2c/busses/i2c-at91-core.c +++ b/drivers/i2c/busses/i2c-at91-core.c @@ -206,19 +206,15 @@ static int at91_twi_probe(struct platform_device *pdev) dev->dev = &pdev->dev; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) - return -ENODEV; + dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); + if (IS_ERR(dev->base)) + return PTR_ERR(dev->base); phy_addr = mem->start; dev->pdata = at91_twi_get_driver_data(pdev); if (!dev->pdata) return -ENODEV; - dev->base = devm_ioremap_resource(&pdev->dev, mem); - if (IS_ERR(dev->base)) - return PTR_ERR(dev->base); - dev->irq = platform_get_irq(pdev, 0); if (dev->irq < 0) return dev->irq; -- GitLab From c71d80d384b4bc133edc8b2f78ec1ea36d1d0cb2 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 14:33:41 +0800 Subject: [PATCH 1042/3445] i2c: iproc: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Acked-by: Ray Jui Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm-iproc.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index 66d8bfabfbf58..508dcdcc9f107 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -1026,7 +1026,6 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev) int irq, ret = 0; struct bcm_iproc_i2c_dev *iproc_i2c; struct i2c_adapter *adap; - struct resource *res; iproc_i2c = devm_kzalloc(&pdev->dev, sizeof(*iproc_i2c), GFP_KERNEL); @@ -1039,15 +1038,12 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev) (enum bcm_iproc_i2c_type)of_device_get_match_data(&pdev->dev); init_completion(&iproc_i2c->done); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - iproc_i2c->base = devm_ioremap_resource(iproc_i2c->device, res); + iproc_i2c->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(iproc_i2c->base)) return PTR_ERR(iproc_i2c->base); if (iproc_i2c->type == IPROC_I2C_NIC) { - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - iproc_i2c->idm_base = devm_ioremap_resource(iproc_i2c->device, - res); + iproc_i2c->idm_base = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(iproc_i2c->idm_base)) return PTR_ERR(iproc_i2c->idm_base); -- GitLab From f9dce8d649abc6d83d7847ff38ac6623cf171667 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 14:33:42 +0800 Subject: [PATCH 1043/3445] i2c: brcmstb: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Kamal Dasu Reviewed-by: Florian Fainelli Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-brcmstb.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c index c778bcca95fea..acee767325441 100644 --- a/drivers/i2c/busses/i2c-brcmstb.c +++ b/drivers/i2c/busses/i2c-brcmstb.c @@ -594,11 +594,10 @@ static int bcm2711_release_bsc(struct brcmstb_i2c_dev *dev) static int brcmstb_i2c_probe(struct platform_device *pdev) { - int rc = 0; struct brcmstb_i2c_dev *dev; struct i2c_adapter *adap; - struct resource *iomem; const char *int_name; + int rc; /* Allocate memory for private data structure */ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); @@ -614,18 +613,15 @@ static int brcmstb_i2c_probe(struct platform_device *pdev) init_completion(&dev->done); /* Map hardware registers */ - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dev->base = devm_ioremap_resource(dev->device, iomem); - if (IS_ERR(dev->base)) { - rc = -ENOMEM; - goto probe_errorout; - } + dev->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(dev->base)) + return PTR_ERR(dev->base); if (of_device_is_compatible(dev->device->of_node, "brcm,bcm2711-hdmi-i2c")) { rc = bcm2711_release_bsc(dev); if (rc) - goto probe_errorout; + return rc; } rc = of_property_read_string(dev->device->of_node, "interrupt-names", @@ -678,16 +674,13 @@ static int brcmstb_i2c_probe(struct platform_device *pdev) adap->dev.of_node = pdev->dev.of_node; rc = i2c_add_adapter(adap); if (rc) - goto probe_errorout; + return rc; dev_info(dev->device, "%s@%dhz registered in %s mode\n", int_name ? int_name : " ", dev->clk_freq_hz, (dev->irq >= 0) ? "interrupt" : "polling"); return 0; - -probe_errorout: - return rc; } static void brcmstb_i2c_remove(struct platform_device *pdev) -- GitLab From 8f4bc41800321f42705bef92d8a28f20626ba660 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 14:33:43 +0800 Subject: [PATCH 1044/3445] i2c: mlxbf: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mlxbf.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c index bf2eaeac3e7cd..b3a73921ab699 100644 --- a/drivers/i2c/busses/i2c-mlxbf.c +++ b/drivers/i2c/busses/i2c-mlxbf.c @@ -1080,13 +1080,7 @@ static int mlxbf_i2c_init_resource(struct platform_device *pdev, if (!tmp_res) return -ENOMEM; - tmp_res->params = platform_get_resource(pdev, IORESOURCE_MEM, type); - if (!tmp_res->params) { - devm_kfree(dev, tmp_res); - return -EIO; - } - - tmp_res->io = devm_ioremap_resource(dev, tmp_res->params); + tmp_res->io = devm_platform_get_and_ioremap_resource(pdev, type, &tmp_res->params); if (IS_ERR(tmp_res->io)) { devm_kfree(dev, tmp_res); return PTR_ERR(tmp_res->io); -- GitLab From 8086ea443d81725718d26b82fc83a47b46ac501d Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 14:33:44 +0800 Subject: [PATCH 1045/3445] i2c: stm32f4: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f4.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-stm32f4.c b/drivers/i2c/busses/i2c-stm32f4.c index 6ad06a5a22b43..ecc54792a66f1 100644 --- a/drivers/i2c/busses/i2c-stm32f4.c +++ b/drivers/i2c/busses/i2c-stm32f4.c @@ -767,8 +767,7 @@ static int stm32f4_i2c_probe(struct platform_device *pdev) if (!i2c_dev) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - i2c_dev->base = devm_ioremap_resource(&pdev->dev, res); + i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(i2c_dev->base)) return PTR_ERR(i2c_dev->base); -- GitLab From 02ebc01dde6694fa7539d0dd8908e19d7f260f97 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 14:33:45 +0800 Subject: [PATCH 1046/3445] i2c: qcom-geni: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qcom-geni.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index b670a67c4fdd0..229353e96e095 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -767,7 +767,6 @@ err_tx: static int geni_i2c_probe(struct platform_device *pdev) { struct geni_i2c_dev *gi2c; - struct resource *res; u32 proto, tx_depth, fifo_disable; int ret; struct device *dev = &pdev->dev; @@ -779,8 +778,7 @@ static int geni_i2c_probe(struct platform_device *pdev) gi2c->se.dev = dev; gi2c->se.wrapper = dev_get_drvdata(dev->parent); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - gi2c->se.base = devm_ioremap_resource(dev, res); + gi2c->se.base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(gi2c->se.base)) return PTR_ERR(gi2c->se.base); -- GitLab From 8f2056ff202db18dba9bd596db249aa6105832c1 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 14:33:46 +0800 Subject: [PATCH 1047/3445] i2c: st: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-st.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c index 25c3521cae0e3..ce2333408904b 100644 --- a/drivers/i2c/busses/i2c-st.c +++ b/drivers/i2c/busses/i2c-st.c @@ -812,8 +812,7 @@ static int st_i2c_probe(struct platform_device *pdev) if (!i2c_dev) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - i2c_dev->base = devm_ioremap_resource(&pdev->dev, res); + i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(i2c_dev->base)) return PTR_ERR(i2c_dev->base); -- GitLab From 3735e4318f1a5b6b769a53c77c4b014999c20fbe Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 14:33:47 +0800 Subject: [PATCH 1048/3445] i2c: sh_mobile: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Reviewed-by: Geert Uytterhoeven Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 67a991b45076e..5adbe62cf6212 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -871,7 +871,6 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) { struct sh_mobile_i2c_data *pd; struct i2c_adapter *adap; - struct resource *res; const struct sh_mobile_dt_config *config; int ret; u32 bus_speed; @@ -893,10 +892,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) pd->dev = &dev->dev; platform_set_drvdata(dev, pd); - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - - pd->res = res; - pd->reg = devm_ioremap_resource(&dev->dev, res); + pd->reg = devm_platform_get_and_ioremap_resource(dev, 0, &pd->res); if (IS_ERR(pd->reg)) return PTR_ERR(pd->reg); @@ -905,7 +901,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) pd->clks_per_count = 1; /* Newer variants come with two new bits in ICIC */ - if (resource_size(res) > 0x17) + if (resource_size(pd->res) > 0x17) pd->flags |= IIC_FLAG_HAS_ICIC67; pm_runtime_enable(&dev->dev); -- GitLab From b15eb80322ff59de57d486e5d923545c1ef0d851 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 14:33:48 +0800 Subject: [PATCH 1049/3445] i2c: s3c2410: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 302c70aadc112..127eb3805facb 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -1033,9 +1033,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk); /* map the registers */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - i2c->regs = devm_ioremap_resource(&pdev->dev, res); - + i2c->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(i2c->regs)) return PTR_ERR(i2c->regs); -- GitLab From 733f41f7029418e2aa6f60f06c1b959a815b575a Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 14:33:49 +0800 Subject: [PATCH 1050/3445] i2c: pxa: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-pxa.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 2eae12c048541..29be05af826b0 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1362,7 +1362,7 @@ static int i2c_pxa_probe(struct platform_device *dev) struct i2c_pxa_platform_data *plat = dev_get_platdata(&dev->dev); enum pxa_i2c_types i2c_type; struct pxa_i2c *i2c; - struct resource *res = NULL; + struct resource *res; int ret, irq; i2c = devm_kzalloc(&dev->dev, sizeof(struct pxa_i2c), GFP_KERNEL); @@ -1379,8 +1379,7 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->adap.dev.of_node = dev->dev.of_node; #endif - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - i2c->reg_base = devm_ioremap_resource(&dev->dev, res); + i2c->reg_base = devm_platform_get_and_ioremap_resource(dev, 0, &res); if (IS_ERR(i2c->reg_base)) return PTR_ERR(i2c->reg_base); -- GitLab From 08e3351b4b4c6d5a9a99c804f06db830402f3594 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 10 Jul 2023 14:33:50 +0800 Subject: [PATCH 1051/3445] i2c: pnx: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yangtao Li Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-pnx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 4ee7db512333d..a12525b3186bc 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -679,8 +679,7 @@ static int i2c_pnx_probe(struct platform_device *pdev) "%s", pdev->name); /* Register I/O resource */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - alg_data->ioaddr = devm_ioremap_resource(&pdev->dev, res); + alg_data->ioaddr = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(alg_data->ioaddr)) return PTR_ERR(alg_data->ioaddr); -- GitLab From 579c7e41507e85dc3eedf998a3dca14a2a1526ad Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 4 Aug 2023 12:15:34 -0700 Subject: [PATCH 1052/3445] Revert "f2fs: clean up w/ sbi->log_sectors_per_block" This reverts commit bfd476623999118d9c509cb0fa9380f2912bc225. Shinichiro Kawasaki reported: When I ran workloads on f2fs using v6.5-rcX with fixes [1][2] and a zoned block devices with 4kb logical block size, I observe mount failure as follows. When I revert this commit, the failure goes away. [ 167.781975][ T1555] F2FS-fs (dm-0): IO Block Size: 4 KB [ 167.890728][ T1555] F2FS-fs (dm-0): Found nat_bits in checkpoint [ 171.482588][ T1555] F2FS-fs (dm-0): Zone without valid block has non-zero write pointer. Reset the write pointer: wp[0x1300,0x8] [ 171.496000][ T1555] F2FS-fs (dm-0): (0) : Unaligned zone reset attempted (block 280000 + 80000) [ 171.505037][ T1555] F2FS-fs (dm-0): Discard zone failed: (errno=-5) The patch replaced "sbi->log_blocksize - SECTOR_SHIFT" with "sbi->log_sectors_per_block". However, I think these two are not equal when the device has 4k logical block size. The former uses Linux kernel sector size 512 byte. The latter use 512b sector size or 4kb sector size depending on the device. mkfs.f2fs obtains logical block size via BLKSSZGET ioctl from the device and reflects it to the value sbi->log_sector_size_per_block. This causes unexpected write pointer calculations in check_zone_write_pointer(). This resulted in unexpected zone reset and the mount failure. [1] https://lkml.kernel.org/linux-f2fs-devel/20230711050101.GA19128@lst.de/ [2] https://lore.kernel.org/linux-f2fs-devel/20230804091556.2372567-1-shinichiro.kawasaki@wdc.com/ Cc: stable@vger.kernel.org Reported-by: Shinichiro Kawasaki Fixes: bfd476623999 ("f2fs: clean up w/ sbi->log_sectors_per_block") Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 0457d620011f6..cbb4bd95ea198 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -4846,17 +4846,17 @@ static int check_zone_write_pointer(struct f2fs_sb_info *sbi, { unsigned int wp_segno, wp_blkoff, zone_secno, zone_segno, segno; block_t zone_block, wp_block, last_valid_block; + unsigned int log_sectors_per_block = sbi->log_blocksize - SECTOR_SHIFT; int i, s, b, ret; struct seg_entry *se; if (zone->type != BLK_ZONE_TYPE_SEQWRITE_REQ) return 0; - wp_block = fdev->start_blk + (zone->wp >> sbi->log_sectors_per_block); + wp_block = fdev->start_blk + (zone->wp >> log_sectors_per_block); wp_segno = GET_SEGNO(sbi, wp_block); wp_blkoff = wp_block - START_BLOCK(sbi, wp_segno); - zone_block = fdev->start_blk + (zone->start >> - sbi->log_sectors_per_block); + zone_block = fdev->start_blk + (zone->start >> log_sectors_per_block); zone_segno = GET_SEGNO(sbi, zone_block); zone_secno = GET_SEC_FROM_SEG(sbi, zone_segno); @@ -4906,7 +4906,7 @@ static int check_zone_write_pointer(struct f2fs_sb_info *sbi, "pointer. Reset the write pointer: wp[0x%x,0x%x]", wp_segno, wp_blkoff); ret = __f2fs_issue_discard_zone(sbi, fdev->bdev, zone_block, - zone->len >> sbi->log_sectors_per_block); + zone->len >> log_sectors_per_block); if (ret) f2fs_err(sbi, "Discard zone failed: %s (errno=%d)", fdev->path, ret); @@ -4967,6 +4967,7 @@ static int fix_curseg_write_pointer(struct f2fs_sb_info *sbi, int type) struct blk_zone zone; unsigned int cs_section, wp_segno, wp_blkoff, wp_sector_off; block_t cs_zone_block, wp_block; + unsigned int log_sectors_per_block = sbi->log_blocksize - SECTOR_SHIFT; sector_t zone_sector; int err; @@ -4978,8 +4979,8 @@ static int fix_curseg_write_pointer(struct f2fs_sb_info *sbi, int type) return 0; /* report zone for the sector the curseg points to */ - zone_sector = (sector_t)(cs_zone_block - zbd->start_blk) << - sbi->log_sectors_per_block; + zone_sector = (sector_t)(cs_zone_block - zbd->start_blk) + << log_sectors_per_block; err = blkdev_report_zones(zbd->bdev, zone_sector, 1, report_one_zone_cb, &zone); if (err != 1) { @@ -4991,10 +4992,10 @@ static int fix_curseg_write_pointer(struct f2fs_sb_info *sbi, int type) if (zone.type != BLK_ZONE_TYPE_SEQWRITE_REQ) return 0; - wp_block = zbd->start_blk + (zone.wp >> sbi->log_sectors_per_block); + wp_block = zbd->start_blk + (zone.wp >> log_sectors_per_block); wp_segno = GET_SEGNO(sbi, wp_block); wp_blkoff = wp_block - START_BLOCK(sbi, wp_segno); - wp_sector_off = zone.wp & GENMASK(sbi->log_sectors_per_block - 1, 0); + wp_sector_off = zone.wp & GENMASK(log_sectors_per_block - 1, 0); if (cs->segno == wp_segno && cs->next_blkoff == wp_blkoff && wp_sector_off == 0) @@ -5021,8 +5022,8 @@ static int fix_curseg_write_pointer(struct f2fs_sb_info *sbi, int type) if (!zbd) return 0; - zone_sector = (sector_t)(cs_zone_block - zbd->start_blk) << - sbi->log_sectors_per_block; + zone_sector = (sector_t)(cs_zone_block - zbd->start_blk) + << log_sectors_per_block; err = blkdev_report_zones(zbd->bdev, zone_sector, 1, report_one_zone_cb, &zone); if (err != 1) { @@ -5040,7 +5041,7 @@ static int fix_curseg_write_pointer(struct f2fs_sb_info *sbi, int type) "Reset the zone: curseg[0x%x,0x%x]", type, cs->segno, cs->next_blkoff); err = __f2fs_issue_discard_zone(sbi, zbd->bdev, cs_zone_block, - zone.len >> sbi->log_sectors_per_block); + zone.len >> log_sectors_per_block); if (err) { f2fs_err(sbi, "Discard zone failed: %s (errno=%d)", zbd->path, err); -- GitLab From 863907a4f53ad567db0767391247d5d0ca398dea Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 10 Jul 2023 14:10:58 +0800 Subject: [PATCH 1053/3445] f2fs: don't handle error case of f2fs_compress_alloc_page() f2fs_compress_alloc_page() uses mempool to allocate memory, it never fail, don't handle error case in its callers. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/compress.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c index 236d890f560b0..9662d635efbe6 100644 --- a/fs/f2fs/compress.c +++ b/fs/f2fs/compress.c @@ -649,13 +649,8 @@ static int f2fs_compress_pages(struct compress_ctx *cc) goto destroy_compress_ctx; } - for (i = 0; i < cc->nr_cpages; i++) { + for (i = 0; i < cc->nr_cpages; i++) cc->cpages[i] = f2fs_compress_alloc_page(); - if (!cc->cpages[i]) { - ret = -ENOMEM; - goto out_free_cpages; - } - } cc->rbuf = f2fs_vmap(cc->rpages, cc->cluster_size); if (!cc->rbuf) { @@ -1574,8 +1569,6 @@ static int f2fs_prepare_decomp_mem(struct decompress_io_ctx *dic, } dic->tpages[i] = f2fs_compress_alloc_page(); - if (!dic->tpages[i]) - return -ENOMEM; } dic->rbuf = f2fs_vmap(dic->tpages, dic->cluster_size); @@ -1656,11 +1649,6 @@ struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc) struct page *page; page = f2fs_compress_alloc_page(); - if (!page) { - ret = -ENOMEM; - goto out_free; - } - f2fs_set_compressed_page(page, cc->inode, start_idx + i + 1, dic); dic->cpages[i] = page; -- GitLab From a3ab55746612247ce3dcaac6de66f5ffc055b9df Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 7 Jul 2023 07:03:13 -0700 Subject: [PATCH 1054/3445] f2fs: flush inode if atomic file is aborted Let's flush the inode being aborted atomic operation to avoid stale dirty inode during eviction in this call stack: f2fs_mark_inode_dirty_sync+0x22/0x40 [f2fs] f2fs_abort_atomic_write+0xc4/0xf0 [f2fs] f2fs_evict_inode+0x3f/0x690 [f2fs] ? sugov_start+0x140/0x140 evict+0xc3/0x1c0 evict_inodes+0x17b/0x210 generic_shutdown_super+0x32/0x120 kill_block_super+0x21/0x50 deactivate_locked_super+0x31/0x90 cleanup_mnt+0x100/0x160 task_work_run+0x59/0x90 do_exit+0x33b/0xa50 do_group_exit+0x2d/0x80 __x64_sys_exit_group+0x14/0x20 do_syscall_64+0x3b/0x90 entry_SYSCALL_64_after_hwframe+0x63/0xcd This triggers f2fs_bug_on() in f2fs_evict_inode: f2fs_bug_on(sbi, is_inode_flag_set(inode, FI_DIRTY_INODE)); This fixes the syzbot report: loop0: detected capacity change from 0 to 131072 F2FS-fs (loop0): invalid crc value F2FS-fs (loop0): Found nat_bits in checkpoint F2FS-fs (loop0): Mounted with checkpoint version = 48b305e4 ------------[ cut here ]------------ kernel BUG at fs/f2fs/inode.c:869! invalid opcode: 0000 [#1] PREEMPT SMP KASAN CPU: 0 PID: 5014 Comm: syz-executor220 Not tainted 6.4.0-syzkaller-11479-g6cd06ab12d1a #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/27/2023 RIP: 0010:f2fs_evict_inode+0x172d/0x1e00 fs/f2fs/inode.c:869 Code: ff df 48 c1 ea 03 80 3c 02 00 0f 85 6a 06 00 00 8b 75 40 ba 01 00 00 00 4c 89 e7 e8 6d ce 06 00 e9 aa fc ff ff e8 63 22 e2 fd <0f> 0b e8 5c 22 e2 fd 48 c7 c0 a8 3a 18 8d 48 ba 00 00 00 00 00 fc RSP: 0018:ffffc90003a6fa00 EFLAGS: 00010293 RAX: 0000000000000000 RBX: 0000000000000001 RCX: 0000000000000000 RDX: ffff8880273b8000 RSI: ffffffff83a2bd0d RDI: 0000000000000007 RBP: ffff888077db91b0 R08: 0000000000000007 R09: 0000000000000000 R10: 0000000000000001 R11: 0000000000000001 R12: ffff888029a3c000 R13: ffff888077db9660 R14: ffff888029a3c0b8 R15: ffff888077db9c50 FS: 0000000000000000(0000) GS:ffff8880b9800000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f1909bb9000 CR3: 00000000276a9000 CR4: 0000000000350ef0 Call Trace: evict+0x2ed/0x6b0 fs/inode.c:665 dispose_list+0x117/0x1e0 fs/inode.c:698 evict_inodes+0x345/0x440 fs/inode.c:748 generic_shutdown_super+0xaf/0x480 fs/super.c:478 kill_block_super+0x64/0xb0 fs/super.c:1417 kill_f2fs_super+0x2af/0x3c0 fs/f2fs/super.c:4704 deactivate_locked_super+0x98/0x160 fs/super.c:330 deactivate_super+0xb1/0xd0 fs/super.c:361 cleanup_mnt+0x2ae/0x3d0 fs/namespace.c:1254 task_work_run+0x16f/0x270 kernel/task_work.c:179 exit_task_work include/linux/task_work.h:38 [inline] do_exit+0xa9a/0x29a0 kernel/exit.c:874 do_group_exit+0xd4/0x2a0 kernel/exit.c:1024 __do_sys_exit_group kernel/exit.c:1035 [inline] __se_sys_exit_group kernel/exit.c:1033 [inline] __x64_sys_exit_group+0x3e/0x50 kernel/exit.c:1033 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x39/0xb0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd RIP: 0033:0x7f309be71a09 Code: Unable to access opcode bytes at 0x7f309be719df. RSP: 002b:00007fff171df518 EFLAGS: 00000246 ORIG_RAX: 00000000000000e7 RAX: ffffffffffffffda RBX: 00007f309bef7330 RCX: 00007f309be71a09 RDX: 000000000000003c RSI: 00000000000000e7 RDI: 0000000000000001 RBP: 0000000000000001 R08: ffffffffffffffc0 R09: 00007f309bef1e40 R10: 0000000000010600 R11: 0000000000000246 R12: 00007f309bef7330 R13: 0000000000000001 R14: 0000000000000000 R15: 0000000000000001 Modules linked in: ---[ end trace 0000000000000000 ]--- RIP: 0010:f2fs_evict_inode+0x172d/0x1e00 fs/f2fs/inode.c:869 Code: ff df 48 c1 ea 03 80 3c 02 00 0f 85 6a 06 00 00 8b 75 40 ba 01 00 00 00 4c 89 e7 e8 6d ce 06 00 e9 aa fc ff ff e8 63 22 e2 fd <0f> 0b e8 5c 22 e2 fd 48 c7 c0 a8 3a 18 8d 48 ba 00 00 00 00 00 fc RSP: 0018:ffffc90003a6fa00 EFLAGS: 00010293 RAX: 0000000000000000 RBX: 0000000000000001 RCX: 0000000000000000 RDX: ffff8880273b8000 RSI: ffffffff83a2bd0d RDI: 0000000000000007 RBP: ffff888077db91b0 R08: 0000000000000007 R09: 0000000000000000 R10: 0000000000000001 R11: 0000000000000001 R12: ffff888029a3c000 R13: ffff888077db9660 R14: ffff888029a3c0b8 R15: ffff888077db9c50 FS: 0000000000000000(0000) GS:ffff8880b9800000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f1909bb9000 CR3: 00000000276a9000 CR4: 0000000000350ef0 Cc: Reported-and-tested-by: syzbot+e1246909d526a9d470fa@syzkaller.appspotmail.com Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index cbb4bd95ea198..b254aaac30310 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -205,6 +205,8 @@ void f2fs_abort_atomic_write(struct inode *inode, bool clean) f2fs_i_size_write(inode, fi->original_i_size); fi->original_i_size = 0; } + /* avoid stale dirty inode during eviction */ + sync_inode_metadata(inode, 0); } static int __replace_atomic_write_block(struct inode *inode, pgoff_t index, -- GitLab From d2d9bb3b6d2fbccb5b33d3a85a2830971625a4ea Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Thu, 19 Jan 2023 10:47:00 -0800 Subject: [PATCH 1055/3445] f2fs: get out of a repeat loop when getting a locked data page https://bugzilla.kernel.org/show_bug.cgi?id=216050 Somehow we're getting a page which has a different mapping. Let's avoid the infinite loop. Cc: Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 5882afe71d82b..ecebc3a139be2 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1389,18 +1389,14 @@ struct page *f2fs_get_lock_data_page(struct inode *inode, pgoff_t index, { struct address_space *mapping = inode->i_mapping; struct page *page; -repeat: + page = f2fs_get_read_data_page(inode, index, 0, for_write, NULL); if (IS_ERR(page)) return page; /* wait for read completion */ lock_page(page); - if (unlikely(page->mapping != mapping)) { - f2fs_put_page(page, 1); - goto repeat; - } - if (unlikely(!PageUptodate(page))) { + if (unlikely(page->mapping != mapping || !PageUptodate(page))) { f2fs_put_page(page, 1); return ERR_PTR(-EIO); } -- GitLab From c709d099a0d2befa2b16c249ef8df722b43e6c28 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 9 Jul 2023 22:23:24 -0700 Subject: [PATCH 1056/3445] f2fs: fix spelling in ABI documentation Correct spelling problems as identified by codespell. Fixes: 9e615dbba41e ("f2fs: add missing description for ipu_policy node") Fixes: b2e4a2b300e5 ("f2fs: expose discard related parameters in sysfs") Fixes: 846ae671ad36 ("f2fs: expose extension_list sysfs entry") Signed-off-by: Randy Dunlap Cc: Jaegeuk Kim Cc: Chao Yu Cc: linux-f2fs-devel@lists.sourceforge.net Cc: Yangtao Li Cc: Konstantin Vyshetsky Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- Documentation/ABI/testing/sysfs-fs-f2fs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index 8140fc98f5aee..ad3d76d37c8ba 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -54,9 +54,9 @@ Description: Controls the in-place-update policy. 0x00 DISABLE disable IPU(=default option in LFS mode) 0x01 FORCE all the time 0x02 SSR if SSR mode is activated - 0x04 UTIL if FS utilization is over threashold + 0x04 UTIL if FS utilization is over threshold 0x08 SSR_UTIL if SSR mode is activated and FS utilization is over - threashold + threshold 0x10 FSYNC activated in fsync path only for high performance flash storages. IPU will be triggered only if the # of dirty pages over min_fsync_blocks. @@ -117,7 +117,7 @@ Date: December 2021 Contact: "Konstantin Vyshetsky" Description: Controls the number of discards a thread will issue at a time. Higher number will allow the discard thread to finish its work - faster, at the cost of higher latency for incomming I/O. + faster, at the cost of higher latency for incoming I/O. What: /sys/fs/f2fs//min_discard_issue_time Date: December 2021 @@ -334,7 +334,7 @@ Description: This indicates how many GC can be failed for the pinned state. 2048 trials is set by default. What: /sys/fs/f2fs//extension_list -Date: Feburary 2018 +Date: February 2018 Contact: "Chao Yu" Description: Used to control configure extension list: - Query: cat /sys/fs/f2fs//extension_list -- GitLab From b5ab3276eb69cacf44ecfb11b2bfab73096ff4e4 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 6 Jul 2023 10:06:14 +0800 Subject: [PATCH 1057/3445] f2fs: fix to avoid mmap vs set_compress_option case Compression option in inode should not be changed after they have been used, however, it may happen in below race case: Thread A Thread B - f2fs_ioc_set_compress_option - check f2fs_is_mmap_file() - check get_dirty_pages() - check F2FS_HAS_BLOCKS() - f2fs_file_mmap - set_inode_flag(FI_MMAP_FILE) - fault - do_page_mkwrite - f2fs_vm_page_mkwrite - f2fs_get_block_locked - fault_dirty_shared_page - set_page_dirty - update i_compress_algorithm - update i_log_cluster_size - update i_cluster_size Avoid such race condition by covering f2fs_file_mmap() w/ i_sem lock, meanwhile add mmap file check condition in f2fs_may_compress() as well. Fixes: e1e8debec656 ("f2fs: add F2FS_IOC_SET_COMPRESS_OPTION ioctl") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 3 ++- fs/f2fs/file.c | 23 ++++++++++++++++++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index c7cb2177b2527..d372bedb0fe4e 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -4483,7 +4483,8 @@ static inline bool f2fs_low_mem_mode(struct f2fs_sb_info *sbi) static inline bool f2fs_may_compress(struct inode *inode) { if (IS_SWAPFILE(inode) || f2fs_is_pinned_file(inode) || - f2fs_is_atomic_file(inode) || f2fs_has_inline_data(inode)) + f2fs_is_atomic_file(inode) || f2fs_has_inline_data(inode) || + f2fs_is_mmap_file(inode)) return false; return S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode); } diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 093039dee9920..d9073afe021fd 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -526,7 +526,11 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma) file_accessed(file); vma->vm_ops = &f2fs_file_vm_ops; + + f2fs_down_read(&F2FS_I(inode)->i_sem); set_inode_flag(inode, FI_MMAP_FILE); + f2fs_up_read(&F2FS_I(inode)->i_sem); + return 0; } @@ -1919,12 +1923,19 @@ static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask) int err = f2fs_convert_inline_inode(inode); if (err) return err; - if (!f2fs_may_compress(inode)) - return -EINVAL; - if (S_ISREG(inode->i_mode) && F2FS_HAS_BLOCKS(inode)) + + f2fs_down_write(&F2FS_I(inode)->i_sem); + if (!f2fs_may_compress(inode) || + (S_ISREG(inode->i_mode) && + F2FS_HAS_BLOCKS(inode))) { + f2fs_up_write(&F2FS_I(inode)->i_sem); return -EINVAL; - if (set_compress_context(inode)) - return -EOPNOTSUPP; + } + err = set_compress_context(inode); + f2fs_up_write(&F2FS_I(inode)->i_sem); + + if (err) + return err; } } @@ -3976,6 +3987,7 @@ static int f2fs_ioc_set_compress_option(struct file *filp, unsigned long arg) file_start_write(filp); inode_lock(inode); + f2fs_down_write(&F2FS_I(inode)->i_sem); if (f2fs_is_mmap_file(inode) || get_dirty_pages(inode)) { ret = -EBUSY; goto out; @@ -3995,6 +4007,7 @@ static int f2fs_ioc_set_compress_option(struct file *filp, unsigned long arg) f2fs_warn(sbi, "compression algorithm is successfully set, " "but current kernel doesn't support this algorithm."); out: + f2fs_up_write(&F2FS_I(inode)->i_sem); inode_unlock(inode); file_end_write(filp); -- GitLab From 51bf8d3c81992ae57beeaf22df78ed7c2782af9d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 7 Jul 2023 10:31:49 +0200 Subject: [PATCH 1058/3445] f2fs: don't reopen the main block device in f2fs_scan_devices f2fs_scan_devices reopens the main device since the very beginning, which has always been useless, and also means that we don't pass the right holder for the reopen, which now leads to a warning as the core super.c holder ops aren't passed in for the reopen. Fixes: 3c62be17d4f5 ("f2fs: support multiple devices") Fixes: 0718afd47f70 ("block: introduce holder ops") Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index ca31163da00a5..30883beb750a5 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1561,7 +1561,8 @@ static void destroy_device_list(struct f2fs_sb_info *sbi) int i; for (i = 0; i < sbi->s_ndevs; i++) { - blkdev_put(FDEV(i).bdev, sbi->sb->s_type); + if (i > 0) + blkdev_put(FDEV(i).bdev, sbi->sb->s_type); #ifdef CONFIG_BLK_DEV_ZONED kvfree(FDEV(i).blkz_seq); #endif @@ -4190,16 +4191,12 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi) sbi->aligned_blksize = true; for (i = 0; i < max_devices; i++) { - - if (i > 0 && !RDEV(i).path[0]) + if (i == 0) + FDEV(0).bdev = sbi->sb->s_bdev; + else if (!RDEV(i).path[0]) break; - if (max_devices == 1) { - /* Single zoned block device mount */ - FDEV(0).bdev = - blkdev_get_by_dev(sbi->sb->s_bdev->bd_dev, mode, - sbi->sb->s_type, NULL); - } else { + if (max_devices > 1) { /* Multi-device mount */ memcpy(FDEV(i).path, RDEV(i).path, MAX_PATH_LEN); FDEV(i).total_segments = @@ -4215,10 +4212,9 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi) FDEV(i).end_blk = FDEV(i).start_blk + (FDEV(i).total_segments << sbi->log_blocks_per_seg) - 1; + FDEV(i).bdev = blkdev_get_by_path(FDEV(i).path, + mode, sbi->sb->s_type, NULL); } - FDEV(i).bdev = blkdev_get_by_path(FDEV(i).path, mode, - sbi->sb->s_type, - NULL); } if (IS_ERR(FDEV(i).bdev)) return PTR_ERR(FDEV(i).bdev); -- GitLab From 3a2c0e55f9bdeda9c3807d6ac23d62f027f6caa9 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 12 Jul 2023 04:08:05 +0800 Subject: [PATCH 1059/3445] f2fs: allow f2fs_ioc_{,de}compress_file to be interrupted This patch allows f2fs_ioc_{,de}compress_file() to be interrupted, so that, userspace won't be blocked when manual {,de}compression on large file is interrupted by signal. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/file.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index d9073afe021fd..79cb6a41f1289 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -4107,6 +4107,12 @@ static int f2fs_ioc_decompress_file(struct file *filp) count -= len; page_idx += len; + + cond_resched(); + if (fatal_signal_pending(current)) { + ret = -EINTR; + break; + } } if (!ret) @@ -4181,6 +4187,12 @@ static int f2fs_ioc_compress_file(struct file *filp) count -= len; page_idx += len; + + cond_resched(); + if (fatal_signal_pending(current)) { + ret = -EINTR; + break; + } } if (!ret) -- GitLab From 025b3602b5fa216fb87bbfa4bff8bb378fe589a0 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 12 Jul 2023 04:08:06 +0800 Subject: [PATCH 1060/3445] f2fs: compress: don't {,de}compress non-full cluster f2fs won't compress non-full cluster in tail of file, let's skip dirtying and rewrite such cluster during f2fs_ioc_{,de}compress_file. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/file.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 79cb6a41f1289..74f79e7c8c020 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -4092,10 +4092,8 @@ static int f2fs_ioc_decompress_file(struct file *filp) last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE); count = last_idx - page_idx; - while (count) { - int len = min(cluster_size, count); - - ret = redirty_blocks(inode, page_idx, len); + while (count && count >= cluster_size) { + ret = redirty_blocks(inode, page_idx, cluster_size); if (ret < 0) break; @@ -4105,8 +4103,8 @@ static int f2fs_ioc_decompress_file(struct file *filp) break; } - count -= len; - page_idx += len; + count -= cluster_size; + page_idx += cluster_size; cond_resched(); if (fatal_signal_pending(current)) { @@ -4172,10 +4170,8 @@ static int f2fs_ioc_compress_file(struct file *filp) last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE); count = last_idx - page_idx; - while (count) { - int len = min(cluster_size, count); - - ret = redirty_blocks(inode, page_idx, len); + while (count && count >= cluster_size) { + ret = redirty_blocks(inode, page_idx, cluster_size); if (ret < 0) break; @@ -4185,8 +4181,8 @@ static int f2fs_ioc_compress_file(struct file *filp) break; } - count -= len; - page_idx += len; + count -= cluster_size; + page_idx += cluster_size; cond_resched(); if (fatal_signal_pending(current)) { -- GitLab From 3cb88bc15937990177df1f7eac6f22ebbed19312 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Kawasaki Date: Fri, 4 Aug 2023 18:15:56 +0900 Subject: [PATCH 1061/3445] f2fs: check zone type before sending async reset zone command The commit 25f9080576b9 ("f2fs: add async reset zone command support") introduced "async reset zone commands" by calling __submit_zone_reset_cmd() in async discard operations. However, __submit_zone_reset_cmd() is called regardless of zone type of discard target zone. When devices have conventional zones, zone reset commands are sent to the conventional zones and cause I/O errors. Avoid the I/O errors by checking that the discard target zone type is sequential write required. If not, handle the discard operation in same manner as non-zoned, regular block devices. For that purpose, add a new helper function f2fs_bdev_index() which gets index of the zone reset target device. Fixes: 25f9080576b9 ("f2fs: add async reset zone command support") Signed-off-by: Shin'ichiro Kawasaki Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 16 ++++++++++++++++ fs/f2fs/segment.c | 39 ++++++++++++++++++++++++++++----------- 2 files changed, 44 insertions(+), 11 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index d372bedb0fe4e..a52830927cb49 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -4423,6 +4423,22 @@ static inline bool f2fs_blkz_is_seq(struct f2fs_sb_info *sbi, int devi, } #endif +static inline int f2fs_bdev_index(struct f2fs_sb_info *sbi, + struct block_device *bdev) +{ + int i; + + if (!f2fs_is_multi_device(sbi)) + return 0; + + for (i = 0; i < sbi->s_ndevs; i++) + if (FDEV(i).bdev == bdev) + return i; + + WARN_ON(1); + return -1; +} + static inline bool f2fs_hw_should_discard(struct f2fs_sb_info *sbi) { return f2fs_sb_has_blkzoned(sbi); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index b254aaac30310..24596d0e6b616 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1260,8 +1260,16 @@ static int __submit_discard_cmd(struct f2fs_sb_info *sbi, #ifdef CONFIG_BLK_DEV_ZONED if (f2fs_sb_has_blkzoned(sbi) && bdev_is_zoned(bdev)) { - __submit_zone_reset_cmd(sbi, dc, flag, wait_list, issued); - return 0; + int devi = f2fs_bdev_index(sbi, bdev); + + if (devi < 0) + return -EINVAL; + + if (f2fs_blkz_is_seq(sbi, devi, dc->di.start)) { + __submit_zone_reset_cmd(sbi, dc, flag, + wait_list, issued); + return 0; + } } #endif @@ -1787,15 +1795,24 @@ static void f2fs_wait_discard_bio(struct f2fs_sb_info *sbi, block_t blkaddr) dc = __lookup_discard_cmd(sbi, blkaddr); #ifdef CONFIG_BLK_DEV_ZONED if (dc && f2fs_sb_has_blkzoned(sbi) && bdev_is_zoned(dc->bdev)) { - /* force submit zone reset */ - if (dc->state == D_PREP) - __submit_zone_reset_cmd(sbi, dc, REQ_SYNC, - &dcc->wait_list, NULL); - dc->ref++; - mutex_unlock(&dcc->cmd_lock); - /* wait zone reset */ - __wait_one_discard_bio(sbi, dc); - return; + int devi = f2fs_bdev_index(sbi, dc->bdev); + + if (devi < 0) { + mutex_unlock(&dcc->cmd_lock); + return; + } + + if (f2fs_blkz_is_seq(sbi, devi, dc->di.start)) { + /* force submit zone reset */ + if (dc->state == D_PREP) + __submit_zone_reset_cmd(sbi, dc, REQ_SYNC, + &dcc->wait_list, NULL); + dc->ref++; + mutex_unlock(&dcc->cmd_lock); + /* wait zone reset */ + __wait_one_discard_bio(sbi, dc); + return; + } } #endif if (dc) { -- GitLab From 2bd4df8fcbc72f58ce3c62ed021ab291ca42de0b Mon Sep 17 00:00:00 2001 From: Chunhai Guo Date: Thu, 3 Aug 2023 22:28:42 +0800 Subject: [PATCH 1062/3445] f2fs: Only lfs mode is allowed with zoned block device feature Now f2fs support four block allocation modes: lfs, adaptive, fragment:segment, fragment:block. Only lfs mode is allowed with zoned block device feature. Fixes: 6691d940b0e0 ("f2fs: introduce fragment allocation mode mount option") Signed-off-by: Chunhai Guo Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 30883beb750a5..26add77f90621 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -862,11 +862,6 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount) if (!name) return -ENOMEM; if (!strcmp(name, "adaptive")) { - if (f2fs_sb_has_blkzoned(sbi)) { - f2fs_warn(sbi, "adaptive mode is not allowed with zoned block device feature"); - kfree(name); - return -EINVAL; - } F2FS_OPTION(sbi).fs_mode = FS_MODE_ADAPTIVE; } else if (!strcmp(name, "lfs")) { F2FS_OPTION(sbi).fs_mode = FS_MODE_LFS; @@ -1331,6 +1326,11 @@ default_check: F2FS_OPTION(sbi).discard_unit = DISCARD_UNIT_SECTION; } + + if (F2FS_OPTION(sbi).fs_mode != FS_MODE_LFS) { + f2fs_info(sbi, "Only lfs mode is allowed with zoned block device feature"); + return -EINVAL; + } #else f2fs_err(sbi, "Zoned block device support is not enabled"); return -EINVAL; -- GitLab From a842a90926b6b96ef38d6a190c27a4a60531a633 Mon Sep 17 00:00:00 2001 From: Minjie Du Date: Mon, 17 Jul 2023 15:11:09 +0800 Subject: [PATCH 1063/3445] f2fs: increase usage of folio_next_index() helper Simplify code pattern of 'folio->index + folio_nr_pages(folio)' by using the existing helper folio_next_index(). Signed-off-by: Minjie Du Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index ecebc3a139be2..5d96977173532 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -3232,8 +3232,7 @@ result: } goto next; } - done_index = folio->index + - folio_nr_pages(folio); + done_index = folio_next_index(folio); done = 1; break; } -- GitLab From 958ccbbf1ce716d77c7cfa79ace50a421c1eed73 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 20 Jul 2023 19:29:53 +0800 Subject: [PATCH 1064/3445] Revert "f2fs: fix to do sanity check on extent cache correctly" syzbot reports a f2fs bug as below: UBSAN: array-index-out-of-bounds in fs/f2fs/f2fs.h:3275:19 index 1409 is out of range for type '__le32[923]' (aka 'unsigned int[923]') Call Trace: __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0x1e7/0x2d0 lib/dump_stack.c:106 ubsan_epilogue lib/ubsan.c:217 [inline] __ubsan_handle_out_of_bounds+0x11c/0x150 lib/ubsan.c:348 inline_data_addr fs/f2fs/f2fs.h:3275 [inline] __recover_inline_status fs/f2fs/inode.c:113 [inline] do_read_inode fs/f2fs/inode.c:480 [inline] f2fs_iget+0x4730/0x48b0 fs/f2fs/inode.c:604 f2fs_fill_super+0x640e/0x80c0 fs/f2fs/super.c:4601 mount_bdev+0x276/0x3b0 fs/super.c:1391 legacy_get_tree+0xef/0x190 fs/fs_context.c:611 vfs_get_tree+0x8c/0x270 fs/super.c:1519 do_new_mount+0x28f/0xae0 fs/namespace.c:3335 do_mount fs/namespace.c:3675 [inline] __do_sys_mount fs/namespace.c:3884 [inline] __se_sys_mount+0x2d9/0x3c0 fs/namespace.c:3861 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x41/0xc0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd The issue was bisected to: commit d48a7b3a72f121655d95b5157c32c7d555e44c05 Author: Chao Yu Date: Mon Jan 9 03:49:20 2023 +0000 f2fs: fix to do sanity check on extent cache correctly The root cause is we applied both v1 and v2 of the patch, v2 is the right fix, so it needs to revert v1 in order to fix reported issue. v1: commit d48a7b3a72f1 ("f2fs: fix to do sanity check on extent cache correctly") https://lore.kernel.org/lkml/20230109034920.492914-1-chao@kernel.org/ v2: commit 269d11948100 ("f2fs: fix to do sanity check on extent cache correctly") https://lore.kernel.org/lkml/20230207134808.1827869-1-chao@kernel.org/ Reported-by: syzbot+601018296973a481f302@syzkaller.appspotmail.com Closes: https://lore.kernel.org/linux-f2fs-devel/000000000000fcf0690600e4d04d@google.com/ Fixes: d48a7b3a72f1 ("f2fs: fix to do sanity check on extent cache correctly") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/inode.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 09e986b050c61..e81725c922cd4 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -475,6 +475,12 @@ static int do_read_inode(struct inode *inode) fi->i_inline_xattr_size = 0; } + if (!sanity_check_inode(inode, node_page)) { + f2fs_put_page(node_page, 1); + f2fs_handle_error(sbi, ERROR_CORRUPTED_INODE); + return -EFSCORRUPTED; + } + /* check data exist */ if (f2fs_has_inline_data(inode) && !f2fs_exist_data(inode)) __recover_inline_status(inode, node_page); @@ -544,12 +550,6 @@ static int do_read_inode(struct inode *inode) f2fs_init_read_extent_tree(inode, node_page); f2fs_init_age_extent_tree(inode); - if (!sanity_check_inode(inode, node_page)) { - f2fs_put_page(node_page, 1); - f2fs_handle_error(sbi, ERROR_CORRUPTED_INODE); - return -EFSCORRUPTED; - } - if (!sanity_check_extent_cache(inode)) { f2fs_put_page(node_page, 1); f2fs_handle_error(sbi, ERROR_CORRUPTED_INODE); -- GitLab From 8874ad7dae8d91d24cc87c545c0073b3b2da5688 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 19 Jul 2023 21:50:45 +0800 Subject: [PATCH 1065/3445] f2fs: fix to update i_ctime in __f2fs_setxattr() generic/728 - output mismatch (see /media/fstests/results//generic/728.out.bad) --- tests/generic/728.out 2023-07-19 07:10:48.362711407 +0000 +++ /media/fstests/results//generic/728.out.bad 2023-07-19 08:39:57.000000000 +0000 QA output created by 728 +Expected ctime to change after setxattr. +Expected ctime to change after removexattr. Silence is golden ... (Run 'diff -u /media/fstests/tests/generic/728.out /media/fstests/results//generic/728.out.bad' to see the entire diff) generic/729 1s It needs to update i_ctime after {set,remove}xattr, fix it. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/xattr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index 476b186b90a6c..71bfa2391ab47 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -757,17 +757,17 @@ static int __f2fs_setxattr(struct inode *inode, int index, if (index == F2FS_XATTR_INDEX_ENCRYPTION && !strcmp(name, F2FS_XATTR_NAME_ENCRYPTION_CONTEXT)) f2fs_set_encrypted_inode(inode); - f2fs_mark_inode_dirty_sync(inode, true); if (!error && S_ISDIR(inode->i_mode)) set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_CP); same: if (is_inode_flag_set(inode, FI_ACL_MODE)) { inode->i_mode = F2FS_I(inode)->i_acl_mode; - inode->i_ctime = current_time(inode); clear_inode_flag(inode, FI_ACL_MODE); } + inode->i_ctime = current_time(inode); + f2fs_mark_inode_dirty_sync(inode, true); exit: kfree(base_addr); return error; -- GitLab From bc3994ffa4cf23f55171943c713366132c3ff45d Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 19 Jul 2023 21:50:46 +0800 Subject: [PATCH 1066/3445] f2fs: remove unneeded check condition in __f2fs_setxattr() It has checked return value of write_all_xattrs(), remove unneeded following check condition. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/xattr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index 71bfa2391ab47..9cc1ca75b2da4 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -757,7 +757,7 @@ static int __f2fs_setxattr(struct inode *inode, int index, if (index == F2FS_XATTR_INDEX_ENCRYPTION && !strcmp(name, F2FS_XATTR_NAME_ENCRYPTION_CONTEXT)) f2fs_set_encrypted_inode(inode); - if (!error && S_ISDIR(inode->i_mode)) + if (S_ISDIR(inode->i_mode)) set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_CP); same: -- GitLab From 9bf1dcbdfdc8892d9cfeaeab02519c0ecf17fe51 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 8 Aug 2023 08:59:48 +0800 Subject: [PATCH 1067/3445] f2fs: fix to account gc stats correctly As reported, status debugfs entry shows inconsistent GC stats as below: GC calls: 6008 (BG: 6161) - data segments : 3053 (BG: 3053) - node segments : 2955 (BG: 2955) Total GC calls is larger than BGGC calls, the reason is: - f2fs_stat_info.call_count accounts total migrated section count by f2fs_gc() - f2fs_stat_info.bg_gc accounts total call times of f2fs_gc() from background gc_thread Another issue is gc_foreground_calls sysfs entry shows total GC call count rather than FGGC call count. This patch changes as below for fix: - account GC calls and migrated segment count separately - support to account migrated section count if it enables large section mode - fix to show correct value in gc_foreground_calls sysfs entry Fixes: fc7100ea2a52 ("f2fs: Add f2fs stats to sysfs") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/debug.c | 24 ++++++++++++++++++------ fs/f2fs/f2fs.h | 42 +++++++++++++++++++++--------------------- fs/f2fs/file.c | 4 ++++ fs/f2fs/gc.c | 13 +++++++------ fs/f2fs/segment.c | 1 + fs/f2fs/super.c | 1 + fs/f2fs/sysfs.c | 4 ++-- 7 files changed, 54 insertions(+), 35 deletions(-) diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index 61c35b59126ec..c7cf453dce838 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -511,12 +511,24 @@ static int stat_show(struct seq_file *s, void *v) seq_printf(s, " - Total : %4d\n", si->nr_total_ckpt); seq_printf(s, " - Cur time : %4d(ms)\n", si->cur_ckpt_time); seq_printf(s, " - Peak time : %4d(ms)\n", si->peak_ckpt_time); - seq_printf(s, "GC calls: %d (BG: %d)\n", - si->call_count, si->bg_gc); - seq_printf(s, " - data segments : %d (%d)\n", - si->data_segs, si->bg_data_segs); - seq_printf(s, " - node segments : %d (%d)\n", - si->node_segs, si->bg_node_segs); + seq_printf(s, "GC calls: %d (gc_thread: %d)\n", + si->gc_call_count[BACKGROUND] + + si->gc_call_count[FOREGROUND], + si->gc_call_count[BACKGROUND]); + if (__is_large_section(sbi)) { + seq_printf(s, " - data sections : %d (BG: %d)\n", + si->gc_secs[DATA][BG_GC] + si->gc_secs[DATA][FG_GC], + si->gc_secs[DATA][BG_GC]); + seq_printf(s, " - node sections : %d (BG: %d)\n", + si->gc_secs[NODE][BG_GC] + si->gc_secs[NODE][FG_GC], + si->gc_secs[NODE][BG_GC]); + } + seq_printf(s, " - data segments : %d (BG: %d)\n", + si->gc_segs[DATA][BG_GC] + si->gc_segs[DATA][FG_GC], + si->gc_segs[DATA][BG_GC]); + seq_printf(s, " - node segments : %d (BG: %d)\n", + si->gc_segs[NODE][BG_GC] + si->gc_segs[NODE][FG_GC], + si->gc_segs[NODE][BG_GC]); seq_puts(s, " - Reclaimed segs :\n"); seq_printf(s, " - Normal : %d\n", sbi->gc_reclaimed_segs[GC_NORMAL]); seq_printf(s, " - Idle CB : %d\n", sbi->gc_reclaimed_segs[GC_IDLE_CB]); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index a52830927cb49..6114babbb26a0 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -3860,6 +3860,12 @@ void f2fs_destroy_recovery_cache(void); /* * debug.c */ +enum { + BACKGROUND, + FOREGROUND, + MAX_CALL_TYPE +}; + #ifdef CONFIG_F2FS_STAT_FS struct f2fs_stat_info { struct list_head stat_list; @@ -3885,7 +3891,7 @@ struct f2fs_stat_info { int nats, dirty_nats, sits, dirty_sits; int free_nids, avail_nids, alloc_nids; int total_count, utilization; - int bg_gc, nr_wb_cp_data, nr_wb_data; + int nr_wb_cp_data, nr_wb_data; int nr_rd_data, nr_rd_node, nr_rd_meta; int nr_dio_read, nr_dio_write; unsigned int io_skip_bggc, other_skip_bggc; @@ -3905,9 +3911,11 @@ struct f2fs_stat_info { int rsvd_segs, overp_segs; int dirty_count, node_pages, meta_pages, compress_pages; int compress_page_hit; - int prefree_count, call_count, cp_count, bg_cp_count; - int tot_segs, node_segs, data_segs, free_segs, free_secs; - int bg_node_segs, bg_data_segs; + int prefree_count, free_segs, free_secs; + int cp_count, bg_cp_count; + int gc_call_count[MAX_CALL_TYPE]; + int gc_segs[2][2]; + int gc_secs[2][2]; int tot_blks, data_blks, node_blks; int bg_data_blks, bg_node_blks; int curseg[NR_CURSEG_TYPE]; @@ -3931,8 +3939,6 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi) #define stat_inc_cp_count(si) ((si)->cp_count++) #define stat_inc_bg_cp_count(si) ((si)->bg_cp_count++) -#define stat_inc_call_count(si) ((si)->call_count++) -#define stat_inc_bggc_count(si) ((si)->bg_gc++) #define stat_io_skip_bggc_count(sbi) ((sbi)->io_skip_bggc++) #define stat_other_skip_bggc_count(sbi) ((sbi)->other_skip_bggc++) #define stat_inc_dirty_inode(sbi, type) ((sbi)->ndirty_inode[type]++) @@ -4017,18 +4023,12 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi) if (cur > max) \ atomic_set(&F2FS_I_SB(inode)->max_aw_cnt, cur); \ } while (0) -#define stat_inc_seg_count(sbi, type, gc_type) \ - do { \ - struct f2fs_stat_info *si = F2FS_STAT(sbi); \ - si->tot_segs++; \ - if ((type) == SUM_TYPE_DATA) { \ - si->data_segs++; \ - si->bg_data_segs += (gc_type == BG_GC) ? 1 : 0; \ - } else { \ - si->node_segs++; \ - si->bg_node_segs += (gc_type == BG_GC) ? 1 : 0; \ - } \ - } while (0) +#define stat_inc_gc_call_count(sbi, foreground) \ + (F2FS_STAT(sbi)->gc_call_count[(foreground)]++) +#define stat_inc_gc_sec_count(sbi, type, gc_type) \ + (F2FS_STAT(sbi)->gc_secs[(type)][(gc_type)]++) +#define stat_inc_gc_seg_count(sbi, type, gc_type) \ + (F2FS_STAT(sbi)->gc_segs[(type)][(gc_type)]++) #define stat_inc_tot_blk_count(si, blks) \ ((si)->tot_blks += (blks)) @@ -4057,8 +4057,6 @@ void f2fs_update_sit_info(struct f2fs_sb_info *sbi); #else #define stat_inc_cp_count(si) do { } while (0) #define stat_inc_bg_cp_count(si) do { } while (0) -#define stat_inc_call_count(si) do { } while (0) -#define stat_inc_bggc_count(si) do { } while (0) #define stat_io_skip_bggc_count(sbi) do { } while (0) #define stat_other_skip_bggc_count(sbi) do { } while (0) #define stat_inc_dirty_inode(sbi, type) do { } while (0) @@ -4086,7 +4084,9 @@ void f2fs_update_sit_info(struct f2fs_sb_info *sbi); #define stat_inc_seg_type(sbi, curseg) do { } while (0) #define stat_inc_block_count(sbi, curseg) do { } while (0) #define stat_inc_inplace_blocks(sbi) do { } while (0) -#define stat_inc_seg_count(sbi, type, gc_type) do { } while (0) +#define stat_inc_gc_call_count(sbi, foreground) do { } while (0) +#define stat_inc_gc_sec_count(sbi, type, gc_type) do { } while (0) +#define stat_inc_gc_seg_count(sbi, type, gc_type) do { } while (0) #define stat_inc_tot_blk_count(si, blks) do { } while (0) #define stat_inc_data_blk_count(sbi, blks, gc_type) do { } while (0) #define stat_inc_node_blk_count(sbi, blks, gc_type) do { } while (0) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 74f79e7c8c020..ff5494c255f6e 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1728,6 +1728,7 @@ next_alloc: if (has_not_enough_free_secs(sbi, 0, GET_SEC_FROM_SEG(sbi, overprovision_segments(sbi)))) { f2fs_down_write(&sbi->gc_lock); + stat_inc_gc_call_count(sbi, FOREGROUND); err = f2fs_gc(sbi, &gc_control); if (err && err != -ENODATA) goto out_err; @@ -2476,6 +2477,7 @@ static int f2fs_ioc_gc(struct file *filp, unsigned long arg) gc_control.init_gc_type = sync ? FG_GC : BG_GC; gc_control.err_gc_skipped = sync; + stat_inc_gc_call_count(sbi, FOREGROUND); ret = f2fs_gc(sbi, &gc_control); out: mnt_drop_write_file(filp); @@ -2519,6 +2521,7 @@ do_more: } gc_control.victim_segno = GET_SEGNO(sbi, range->start); + stat_inc_gc_call_count(sbi, FOREGROUND); ret = f2fs_gc(sbi, &gc_control); if (ret) { if (ret == -EBUSY) @@ -3001,6 +3004,7 @@ static int f2fs_ioc_flush_device(struct file *filp, unsigned long arg) sm->last_victim[ALLOC_NEXT] = end_segno + 1; gc_control.victim_segno = start_segno; + stat_inc_gc_call_count(sbi, FOREGROUND); ret = f2fs_gc(sbi, &gc_control); if (ret == -EAGAIN) ret = 0; diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 01effd3fcb6c7..68c3250fb3d23 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -121,8 +121,8 @@ static int gc_thread_func(void *data) else increase_sleep_time(gc_th, &wait_ms); do_gc: - if (!foreground) - stat_inc_bggc_count(sbi->stat_info); + stat_inc_gc_call_count(sbi, foreground ? + FOREGROUND : BACKGROUND); sync_mode = F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_SYNC; @@ -1685,6 +1685,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, int seg_freed = 0, migrated = 0; unsigned char type = IS_DATASEG(get_seg_entry(sbi, segno)->type) ? SUM_TYPE_DATA : SUM_TYPE_NODE; + unsigned char data_type = (type == SUM_TYPE_DATA) ? DATA : NODE; int submitted = 0; if (__is_large_section(sbi)) @@ -1766,7 +1767,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, segno, gc_type, force_migrate); - stat_inc_seg_count(sbi, type, gc_type); + stat_inc_gc_seg_count(sbi, data_type, gc_type); sbi->gc_reclaimed_segs[sbi->gc_mode]++; migrated++; @@ -1783,12 +1784,12 @@ skip: } if (submitted) - f2fs_submit_merged_write(sbi, - (type == SUM_TYPE_NODE) ? NODE : DATA); + f2fs_submit_merged_write(sbi, data_type); blk_finish_plug(&plug); - stat_inc_call_count(sbi->stat_info); + if (migrated) + stat_inc_gc_sec_count(sbi, data_type, gc_type); return seg_freed; } diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 24596d0e6b616..d07e32e82aa9d 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -435,6 +435,7 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need) .err_gc_skipped = false, .nr_free_secs = 1 }; f2fs_down_write(&sbi->gc_lock); + stat_inc_gc_call_count(sbi, FOREGROUND); f2fs_gc(sbi, &gc_control); } } diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 26add77f90621..2bbef48bc5a3a 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -2206,6 +2206,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi) .nr_free_secs = 1 }; f2fs_down_write(&sbi->gc_lock); + stat_inc_gc_call_count(sbi, FOREGROUND); err = f2fs_gc(sbi, &gc_control); if (err == -ENODATA) { err = 0; diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index 48b7e0073884a..95a301581b915 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -974,8 +974,8 @@ F2FS_SBI_GENERAL_RO_ATTR(unusable_blocks_per_sec); #ifdef CONFIG_F2FS_STAT_FS STAT_INFO_RO_ATTR(cp_foreground_calls, cp_count); STAT_INFO_RO_ATTR(cp_background_calls, bg_cp_count); -STAT_INFO_RO_ATTR(gc_foreground_calls, call_count); -STAT_INFO_RO_ATTR(gc_background_calls, bg_gc); +STAT_INFO_RO_ATTR(gc_foreground_calls, gc_call_count[FOREGROUND]); +STAT_INFO_RO_ATTR(gc_background_calls, gc_call_count[BACKGROUND]); #endif /* FAULT_INFO ATTR */ -- GitLab From eb61c2cca2eb2110cc7b61a7bc15b3850977a778 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 8 Aug 2023 08:59:49 +0800 Subject: [PATCH 1068/3445] f2fs: fix to account cp stats correctly cp_foreground_calls sysfs entry shows total CP call count rather than foreground CP call count, fix it. Fixes: fc7100ea2a52 ("f2fs: Add f2fs stats to sysfs") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 2 +- fs/f2fs/debug.c | 9 ++++++++- fs/f2fs/f2fs.h | 25 ++++++++++++++----------- fs/f2fs/gc.c | 5 +++++ fs/f2fs/recovery.c | 1 + fs/f2fs/segment.c | 3 ++- fs/f2fs/super.c | 8 +++++++- fs/f2fs/sysfs.c | 14 ++++++++++++-- 8 files changed, 50 insertions(+), 17 deletions(-) diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 8fd3b7f9fb88e..b0597a539fc54 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -1701,9 +1701,9 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) } f2fs_restore_inmem_curseg(sbi); + stat_inc_cp_count(sbi); stop: unblock_operations(sbi); - stat_inc_cp_count(sbi->stat_info); if (cpc->reason & CP_RECOVERY) f2fs_notice(sbi, "checkpoint: version = %llx", ckpt_ver); diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index c7cf453dce838..fdbf994f12718 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -215,6 +215,9 @@ static void update_general_status(struct f2fs_sb_info *sbi) si->valid_blks[type] += blks; } + for (i = 0; i < MAX_CALL_TYPE; i++) + si->cp_call_count[i] = atomic_read(&sbi->cp_call_count[i]); + for (i = 0; i < 2; i++) { si->segment_count[i] = sbi->segment_count[i]; si->block_count[i] = sbi->block_count[i]; @@ -497,7 +500,9 @@ static int stat_show(struct seq_file *s, void *v) seq_printf(s, " - Prefree: %d\n - Free: %d (%d)\n\n", si->prefree_count, si->free_segs, si->free_secs); seq_printf(s, "CP calls: %d (BG: %d)\n", - si->cp_count, si->bg_cp_count); + si->cp_call_count[TOTAL_CALL], + si->cp_call_count[BACKGROUND]); + seq_printf(s, "CP count: %d\n", si->cp_count); seq_printf(s, " - cp blocks : %u\n", si->meta_count[META_CP]); seq_printf(s, " - sit blocks : %u\n", si->meta_count[META_SIT]); @@ -699,6 +704,8 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) atomic_set(&sbi->inplace_count, 0); for (i = META_CP; i < META_MAX; i++) atomic_set(&sbi->meta_count[i], 0); + for (i = 0; i < MAX_CALL_TYPE; i++) + atomic_set(&sbi->cp_call_count[i], 0); atomic_set(&sbi->max_aw_cnt, 0); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 6114babbb26a0..c602ff2403b67 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1383,6 +1383,13 @@ enum errors_option { MOUNT_ERRORS_PANIC, /* panic on errors */ }; +enum { + BACKGROUND, + FOREGROUND, + MAX_CALL_TYPE, + TOTAL_CALL = FOREGROUND, +}; + static inline int f2fs_test_bit(unsigned int nr, char *addr); static inline void f2fs_set_bit(unsigned int nr, char *addr); static inline void f2fs_clear_bit(unsigned int nr, char *addr); @@ -1695,6 +1702,7 @@ struct f2fs_sb_info { unsigned int io_skip_bggc; /* skip background gc for in-flight IO */ unsigned int other_skip_bggc; /* skip background gc for other reasons */ unsigned int ndirty_inode[NR_INODE_TYPE]; /* # of dirty inodes */ + atomic_t cp_call_count[MAX_CALL_TYPE]; /* # of cp call */ #endif spinlock_t stat_lock; /* lock for stat operations */ @@ -3860,12 +3868,6 @@ void f2fs_destroy_recovery_cache(void); /* * debug.c */ -enum { - BACKGROUND, - FOREGROUND, - MAX_CALL_TYPE -}; - #ifdef CONFIG_F2FS_STAT_FS struct f2fs_stat_info { struct list_head stat_list; @@ -3912,7 +3914,7 @@ struct f2fs_stat_info { int dirty_count, node_pages, meta_pages, compress_pages; int compress_page_hit; int prefree_count, free_segs, free_secs; - int cp_count, bg_cp_count; + int cp_call_count[MAX_CALL_TYPE], cp_count; int gc_call_count[MAX_CALL_TYPE]; int gc_segs[2][2]; int gc_secs[2][2]; @@ -3937,8 +3939,9 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi) return (struct f2fs_stat_info *)sbi->stat_info; } -#define stat_inc_cp_count(si) ((si)->cp_count++) -#define stat_inc_bg_cp_count(si) ((si)->bg_cp_count++) +#define stat_inc_cp_call_count(sbi, foreground) \ + atomic_inc(&sbi->cp_call_count[(foreground)]) +#define stat_inc_cp_count(si) (F2FS_STAT(sbi)->cp_count++) #define stat_io_skip_bggc_count(sbi) ((sbi)->io_skip_bggc++) #define stat_other_skip_bggc_count(sbi) ((sbi)->other_skip_bggc++) #define stat_inc_dirty_inode(sbi, type) ((sbi)->ndirty_inode[type]++) @@ -4055,8 +4058,8 @@ void __init f2fs_create_root_stats(void); void f2fs_destroy_root_stats(void); void f2fs_update_sit_info(struct f2fs_sb_info *sbi); #else -#define stat_inc_cp_count(si) do { } while (0) -#define stat_inc_bg_cp_count(si) do { } while (0) +#define stat_inc_cp_call_count(sbi, foreground) do { } while (0) +#define stat_inc_cp_count(sbi) do { } while (0) #define stat_io_skip_bggc_count(sbi) do { } while (0) #define stat_other_skip_bggc_count(sbi) do { } while (0) #define stat_inc_dirty_inode(sbi, type) do { } while (0) diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 68c3250fb3d23..6690323fff83b 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -1840,6 +1840,7 @@ gc_more: * secure free segments which doesn't need fggc any more. */ if (prefree_segments(sbi)) { + stat_inc_cp_call_count(sbi, TOTAL_CALL); ret = f2fs_write_checkpoint(sbi, &cpc); if (ret) goto stop; @@ -1888,6 +1889,7 @@ retry: round++; if (skipped_round > MAX_SKIP_GC_COUNT && skipped_round * 2 >= round) { + stat_inc_cp_call_count(sbi, TOTAL_CALL); ret = f2fs_write_checkpoint(sbi, &cpc); goto stop; } @@ -1903,6 +1905,7 @@ retry: */ if (free_sections(sbi) <= upper_secs + NR_GC_CHECKPOINT_SECS && prefree_segments(sbi)) { + stat_inc_cp_call_count(sbi, TOTAL_CALL); ret = f2fs_write_checkpoint(sbi, &cpc); if (ret) goto stop; @@ -2030,6 +2033,7 @@ static int free_segment_range(struct f2fs_sb_info *sbi, if (gc_only) goto out; + stat_inc_cp_call_count(sbi, TOTAL_CALL); err = f2fs_write_checkpoint(sbi, &cpc); if (err) goto out; @@ -2222,6 +2226,7 @@ out_drop_write: clear_sbi_flag(sbi, SBI_IS_RESIZEFS); set_sbi_flag(sbi, SBI_IS_DIRTY); + stat_inc_cp_call_count(sbi, TOTAL_CALL); err = f2fs_write_checkpoint(sbi, &cpc); if (err) { update_fs_metadata(sbi, secs); diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 4e7d4ceeb084c..e91f4619aa5bb 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -924,6 +924,7 @@ skip: struct cp_control cpc = { .reason = CP_RECOVERY, }; + stat_inc_cp_call_count(sbi, TOTAL_CALL); err = f2fs_write_checkpoint(sbi, &cpc); } } diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index d07e32e82aa9d..35d1e1dd849fd 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -513,8 +513,8 @@ do_sync: mutex_unlock(&sbi->flush_lock); } + stat_inc_cp_call_count(sbi, BACKGROUND); f2fs_sync_fs(sbi->sb, 1); - stat_inc_bg_cp_count(sbi->stat_info); } static int __submit_flush_wait(struct f2fs_sb_info *sbi, @@ -3248,6 +3248,7 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) goto out; f2fs_down_write(&sbi->gc_lock); + stat_inc_cp_call_count(sbi, TOTAL_CALL); err = f2fs_write_checkpoint(sbi, &cpc); f2fs_up_write(&sbi->gc_lock); if (err) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 2bbef48bc5a3a..a067466a694c9 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1601,6 +1601,7 @@ static void f2fs_put_super(struct super_block *sb) struct cp_control cpc = { .reason = CP_UMOUNT, }; + stat_inc_cp_call_count(sbi, TOTAL_CALL); err = f2fs_write_checkpoint(sbi, &cpc); } @@ -1610,6 +1611,7 @@ static void f2fs_put_super(struct super_block *sb) struct cp_control cpc = { .reason = CP_UMOUNT | CP_TRIMMED, }; + stat_inc_cp_call_count(sbi, TOTAL_CALL); err = f2fs_write_checkpoint(sbi, &cpc); } @@ -1706,8 +1708,10 @@ int f2fs_sync_fs(struct super_block *sb, int sync) if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) return -EAGAIN; - if (sync) + if (sync) { + stat_inc_cp_call_count(sbi, TOTAL_CALL); err = f2fs_issue_checkpoint(sbi); + } return err; } @@ -2232,6 +2236,7 @@ skip_gc: f2fs_down_write(&sbi->gc_lock); cpc.reason = CP_PAUSE; set_sbi_flag(sbi, SBI_CP_DISABLED); + stat_inc_cp_call_count(sbi, TOTAL_CALL); err = f2fs_write_checkpoint(sbi, &cpc); if (err) goto out_unlock; @@ -4868,6 +4873,7 @@ static void kill_f2fs_super(struct super_block *sb) struct cp_control cpc = { .reason = CP_UMOUNT, }; + stat_inc_cp_call_count(sbi, TOTAL_CALL); f2fs_write_checkpoint(sbi, &cpc); } diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index 95a301581b915..417fae96890f6 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -356,6 +356,16 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, if (!strcmp(a->attr.name, "revoked_atomic_block")) return sysfs_emit(buf, "%llu\n", sbi->revoked_atomic_block); +#ifdef CONFIG_F2FS_STAT_FS + if (!strcmp(a->attr.name, "cp_foreground_calls")) + return sysfs_emit(buf, "%d\n", + atomic_read(&sbi->cp_call_count[TOTAL_CALL]) - + atomic_read(&sbi->cp_call_count[BACKGROUND])); + if (!strcmp(a->attr.name, "cp_background_calls")) + return sysfs_emit(buf, "%d\n", + atomic_read(&sbi->cp_call_count[BACKGROUND])); +#endif + ui = (unsigned int *)(ptr + a->offset); return sysfs_emit(buf, "%u\n", *ui); @@ -972,8 +982,8 @@ F2FS_SBI_GENERAL_RO_ATTR(unusable_blocks_per_sec); /* STAT_INFO ATTR */ #ifdef CONFIG_F2FS_STAT_FS -STAT_INFO_RO_ATTR(cp_foreground_calls, cp_count); -STAT_INFO_RO_ATTR(cp_background_calls, bg_cp_count); +STAT_INFO_RO_ATTR(cp_foreground_calls, cp_call_count[FOREGROUND]); +STAT_INFO_RO_ATTR(cp_background_calls, cp_call_count[BACKGROUND]); STAT_INFO_RO_ATTR(gc_foreground_calls, gc_call_count[FOREGROUND]); STAT_INFO_RO_ATTR(gc_background_calls, gc_call_count[BACKGROUND]); #endif -- GitLab From 0cc81b1ad51287847e494e055e5d3426f95e7921 Mon Sep 17 00:00:00 2001 From: Zhiguo Niu Date: Thu, 10 Aug 2023 16:40:00 +0800 Subject: [PATCH 1069/3445] f2fs: should update REQ_TIME for direct write The sending interval of discard and GC should also consider direct write requests; filesystem is not idle if there is direct write. Signed-off-by: Zhiguo Niu Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/file.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index ff5494c255f6e..047942d2ec5da 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -4604,6 +4604,7 @@ static int f2fs_dio_write_end_io(struct kiocb *iocb, ssize_t size, int error, dec_page_count(sbi, F2FS_DIO_WRITE); if (error) return error; + f2fs_update_time(sbi, REQ_TIME); f2fs_update_iostat(sbi, NULL, APP_DIRECT_IO, size); return 0; } -- GitLab From b6a46f7263bd8ba0e545d79bd034c412f32b5875 Mon Sep 17 00:00:00 2001 From: Aaron Tomlin Date: Tue, 8 Aug 2023 13:03:29 +0100 Subject: [PATCH 1070/3445] workqueue: Rename rescuer kworker Each CPU-specific and unbound kworker kthread conforms to a particular naming scheme. However, this does not extend to the rescuer kworker. At present, a rescuer kworker is simply named according to its workqueue's name. This can be cryptic. This patch modifies a rescuer to follow the kworker naming scheme. The "R" is indicative of a rescuer and after "-" is its workqueue's name e.g. "kworker/R-ext4-rsv-conver". tj: Use "R" instead of "r" as the prefix to make it more distinctive and consistent with how highpri pools are marked. Signed-off-by: Aaron Tomlin Signed-off-by: Tejun Heo --- kernel/workqueue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 789e11e72a4a4..d4364d3d8aaa4 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -4642,7 +4642,7 @@ static int init_rescuer(struct workqueue_struct *wq) } rescuer->rescue_wq = wq; - rescuer->task = kthread_create(rescuer_thread, rescuer, "%s", wq->name); + rescuer->task = kthread_create(rescuer_thread, rescuer, "kworker/R-%s", wq->name); if (IS_ERR(rescuer->task)) { ret = PTR_ERR(rescuer->task); pr_err("workqueue: Failed to create a rescuer kthread for wq \"%s\": %pe", -- GitLab From 82b90b6c5b38e457c7081d50dff11ecbafc1e61a Mon Sep 17 00:00:00 2001 From: Lu Jialin Date: Thu, 10 Aug 2023 11:25:28 +0000 Subject: [PATCH 1071/3445] cgroup:namespace: Remove unused cgroup_namespaces_init() cgroup_namspace_init() just return 0. Therefore, there is no need to call it during start_kernel. Just remove it. Fixes: a79a908fd2b0 ("cgroup: introduce cgroup namespaces") Signed-off-by: Lu Jialin Signed-off-by: Tejun Heo --- kernel/cgroup/namespace.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/kernel/cgroup/namespace.c b/kernel/cgroup/namespace.c index 0d5c29879a50b..144a464e45c66 100644 --- a/kernel/cgroup/namespace.c +++ b/kernel/cgroup/namespace.c @@ -149,9 +149,3 @@ const struct proc_ns_operations cgroupns_operations = { .install = cgroupns_install, .owner = cgroupns_owner, }; - -static __init int cgroup_namespaces_init(void) -{ - return 0; -} -subsys_initcall(cgroup_namespaces_init); -- GitLab From 811e0ce9e6499a0c71c359a2b7e2bd6a5ed8e58f Mon Sep 17 00:00:00 2001 From: Kashyap Desai Date: Mon, 14 Aug 2023 10:00:18 -0700 Subject: [PATCH 1072/3445] RDMA/bnxt_re: Initialize mutex dbq_lock Fix the missing dbq_lock mutex initialization Fixes: 2ad4e6303a6d ("RDMA/bnxt_re: Implement doorbell pacing algorithm") Signed-off-by: Kashyap Desai Signed-off-by: Selvin Xavier Link: https://lore.kernel.org/r/1692032419-21680-1-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index f34ce490500fd..061a89bbb3b0d 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -920,6 +920,7 @@ static struct bnxt_re_dev *bnxt_re_dev_add(struct bnxt_aux_priv *aux_priv, rdev->id = rdev->en_dev->pdev->devfn; INIT_LIST_HEAD(&rdev->qp_list); mutex_init(&rdev->qp_lock); + mutex_init(&rdev->pacing.dbq_lock); atomic_set(&rdev->stats.res.qp_count, 0); atomic_set(&rdev->stats.res.cq_count, 0); atomic_set(&rdev->stats.res.srq_count, 0); -- GitLab From 213d2b9bb2d6aa50f9cbc02a0eea2096899d2e75 Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Mon, 14 Aug 2023 10:00:19 -0700 Subject: [PATCH 1073/3445] RDMA/bnxt_re: Protect the PD table bitmap Syncrhonization is required to avoid simultaneous allocation of the PD. Add a new mutex lock to handle allocation from the PD table. Signed-off-by: Kashyap Desai Signed-off-by: Selvin Xavier Link: https://lore.kernel.org/r/1692032419-21680-2-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 2 +- drivers/infiniband/hw/bnxt_re/qplib_res.c | 26 +++++++++++++++++------ drivers/infiniband/hw/bnxt_re/qplib_res.h | 4 +++- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index c0a7181247f6d..b19334ce93c33 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -619,7 +619,7 @@ int bnxt_re_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata) int rc = 0; pd->rdev = rdev; - if (bnxt_qplib_alloc_pd(&rdev->qplib_res.pd_tbl, &pd->qplib_pd)) { + if (bnxt_qplib_alloc_pd(&rdev->qplib_res, &pd->qplib_pd)) { ibdev_err(&rdev->ibdev, "Failed to allocate HW PD"); rc = -ENOMEM; goto fail; diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.c b/drivers/infiniband/hw/bnxt_re/qplib_res.c index 6f1e8b721ad0b..79c43c26d5117 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c @@ -642,31 +642,44 @@ static void bnxt_qplib_init_sgid_tbl(struct bnxt_qplib_sgid_tbl *sgid_tbl, } /* PDs */ -int bnxt_qplib_alloc_pd(struct bnxt_qplib_pd_tbl *pdt, struct bnxt_qplib_pd *pd) +int bnxt_qplib_alloc_pd(struct bnxt_qplib_res *res, struct bnxt_qplib_pd *pd) { + struct bnxt_qplib_pd_tbl *pdt = &res->pd_tbl; u32 bit_num; + int rc = 0; + mutex_lock(&res->pd_tbl_lock); bit_num = find_first_bit(pdt->tbl, pdt->max); - if (bit_num == pdt->max) - return -ENOMEM; + if (bit_num == pdt->max) { + rc = -ENOMEM; + goto exit; + } /* Found unused PD */ clear_bit(bit_num, pdt->tbl); pd->id = bit_num; - return 0; +exit: + mutex_unlock(&res->pd_tbl_lock); + return rc; } int bnxt_qplib_dealloc_pd(struct bnxt_qplib_res *res, struct bnxt_qplib_pd_tbl *pdt, struct bnxt_qplib_pd *pd) { + int rc = 0; + + mutex_lock(&res->pd_tbl_lock); if (test_and_set_bit(pd->id, pdt->tbl)) { dev_warn(&res->pdev->dev, "Freeing an unused PD? pdn = %d\n", pd->id); - return -EINVAL; + rc = -EINVAL; + goto exit; } pd->id = 0; - return 0; +exit: + mutex_unlock(&res->pd_tbl_lock); + return rc; } static void bnxt_qplib_free_pd_tbl(struct bnxt_qplib_pd_tbl *pdt) @@ -691,6 +704,7 @@ static int bnxt_qplib_alloc_pd_tbl(struct bnxt_qplib_res *res, pdt->max = max; memset((u8 *)pdt->tbl, 0xFF, bytes); + mutex_init(&res->pd_tbl_lock); return 0; } diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.h b/drivers/infiniband/hw/bnxt_re/qplib_res.h index 57161d303c257..5949f004f7856 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.h @@ -277,6 +277,8 @@ struct bnxt_qplib_res { struct net_device *netdev; struct bnxt_qplib_rcfw *rcfw; struct bnxt_qplib_pd_tbl pd_tbl; + /* To protect the pd table bit map */ + struct mutex pd_tbl_lock; struct bnxt_qplib_sgid_tbl sgid_tbl; struct bnxt_qplib_dpi_tbl dpi_tbl; /* To protect the dpi table bit map */ @@ -368,7 +370,7 @@ void bnxt_qplib_free_hwq(struct bnxt_qplib_res *res, struct bnxt_qplib_hwq *hwq); int bnxt_qplib_alloc_init_hwq(struct bnxt_qplib_hwq *hwq, struct bnxt_qplib_hwq_attr *hwq_attr); -int bnxt_qplib_alloc_pd(struct bnxt_qplib_pd_tbl *pd_tbl, +int bnxt_qplib_alloc_pd(struct bnxt_qplib_res *res, struct bnxt_qplib_pd *pd); int bnxt_qplib_dealloc_pd(struct bnxt_qplib_res *res, struct bnxt_qplib_pd_tbl *pd_tbl, -- GitLab From 122b159d9f1374a7252c927df2b2a575f77de85b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 8 Aug 2023 00:32:41 +0900 Subject: [PATCH 1074/3445] mips: remove unneeded #include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no EXPORT_SYMBOL line there, hence #include is unneeded. Signed-off-by: Masahiro Yamada Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Bogendoerfer --- arch/mips/kernel/octeon_switch.S | 1 - arch/mips/kernel/r2300_switch.S | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/mips/kernel/octeon_switch.S b/arch/mips/kernel/octeon_switch.S index 9b7c8ab6f08c6..447a3ea14aa11 100644 --- a/arch/mips/kernel/octeon_switch.S +++ b/arch/mips/kernel/octeon_switch.S @@ -11,7 +11,6 @@ * written by Carsten Langgaard, carstenl@mips.com */ #include -#include #include #include #include diff --git a/arch/mips/kernel/r2300_switch.S b/arch/mips/kernel/r2300_switch.S index 71b1aafae1bb1..48e63943e6f76 100644 --- a/arch/mips/kernel/r2300_switch.S +++ b/arch/mips/kernel/r2300_switch.S @@ -13,7 +13,6 @@ */ #include #include -#include #include #include #include -- GitLab From 9259e15b3f27fa5cc5999db554bce713f32769c3 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 8 Aug 2023 00:32:42 +0900 Subject: [PATCH 1075/3445] mips: replace #include with #include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit ddb5cdbafaaa ("kbuild: generate KSYMTAB entries by modpost") deprecated , which is now a wrapper of . Replace #include with #include . After all the lines are converted, and will be removed. Signed-off-by: Masahiro Yamada Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Bogendoerfer --- arch/mips/cavium-octeon/octeon-memcpy.S | 2 +- arch/mips/kernel/mcount.S | 2 +- arch/mips/kernel/r2300_fpu.S | 2 +- arch/mips/kernel/r4k_fpu.S | 2 +- arch/mips/lib/csum_partial.S | 2 +- arch/mips/lib/memcpy.S | 2 +- arch/mips/lib/memset.S | 2 +- arch/mips/lib/strncpy_user.S | 2 +- arch/mips/lib/strnlen_user.S | 2 +- arch/mips/mm/page-funcs.S | 2 +- arch/mips/mm/tlb-funcs.S | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/mips/cavium-octeon/octeon-memcpy.S b/arch/mips/cavium-octeon/octeon-memcpy.S index 25860fba6218d..fef0c6de3fa10 100644 --- a/arch/mips/cavium-octeon/octeon-memcpy.S +++ b/arch/mips/cavium-octeon/octeon-memcpy.S @@ -13,9 +13,9 @@ * Mnemonic names for arguments to memcpy/__copy_user */ +#include #include #include -#include #include #define dst a0 diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S index cff52b283e038..fcec579f64e96 100644 --- a/arch/mips/kernel/mcount.S +++ b/arch/mips/kernel/mcount.S @@ -10,7 +10,7 @@ * Author: Wu Zhangjin */ -#include +#include #include #include #include diff --git a/arch/mips/kernel/r2300_fpu.S b/arch/mips/kernel/r2300_fpu.S index 6c745aa9e8259..c000b22e3fcd1 100644 --- a/arch/mips/kernel/r2300_fpu.S +++ b/arch/mips/kernel/r2300_fpu.S @@ -11,10 +11,10 @@ * Further modifications to make this work: * Copyright (c) 1998 Harald Koerfgen */ +#include #include #include #include -#include #include #include #include diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index 4e8c98517d9d4..4bb97ee899042 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -12,10 +12,10 @@ * Copyright (C) 2000 MIPS Technologies, Inc. * Copyright (C) 1999, 2001 Silicon Graphics, Inc. */ +#include #include #include #include -#include #include #include #include diff --git a/arch/mips/lib/csum_partial.S b/arch/mips/lib/csum_partial.S index 7767137c3e49a..3d2ff4118d799 100644 --- a/arch/mips/lib/csum_partial.S +++ b/arch/mips/lib/csum_partial.S @@ -11,9 +11,9 @@ * Copyright (C) 2014 Imagination Technologies Ltd. */ #include +#include #include #include -#include #include #ifdef CONFIG_64BIT diff --git a/arch/mips/lib/memcpy.S b/arch/mips/lib/memcpy.S index 18a43f2e29c81..a4b4e805ff135 100644 --- a/arch/mips/lib/memcpy.S +++ b/arch/mips/lib/memcpy.S @@ -32,9 +32,9 @@ #undef CONFIG_CPU_HAS_PREFETCH #endif +#include #include #include -#include #include #define dst a0 diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S index 0b342bae9a98c..79405c32cc853 100644 --- a/arch/mips/lib/memset.S +++ b/arch/mips/lib/memset.S @@ -8,9 +8,9 @@ * Copyright (C) 2007 by Maciej W. Rozycki * Copyright (C) 2011, 2012 MIPS Technologies, Inc. */ +#include #include #include -#include #include #if LONGSIZE == 4 diff --git a/arch/mips/lib/strncpy_user.S b/arch/mips/lib/strncpy_user.S index 13aaa9927ad12..94f4203563c1c 100644 --- a/arch/mips/lib/strncpy_user.S +++ b/arch/mips/lib/strncpy_user.S @@ -7,9 +7,9 @@ * Copyright (C) 2011 MIPS Technologies, Inc. */ #include +#include #include #include -#include #include #define EX(insn,reg,addr,handler) \ diff --git a/arch/mips/lib/strnlen_user.S b/arch/mips/lib/strnlen_user.S index 6de31b616f9c1..c192a6f6cd841 100644 --- a/arch/mips/lib/strnlen_user.S +++ b/arch/mips/lib/strnlen_user.S @@ -6,9 +6,9 @@ * Copyright (c) 1996, 1998, 1999, 2004 by Ralf Baechle * Copyright (c) 1999 Silicon Graphics, Inc. */ +#include #include #include -#include #include #define EX(insn,reg,addr,handler) \ diff --git a/arch/mips/mm/page-funcs.S b/arch/mips/mm/page-funcs.S index 43181ac0a1afc..42d0516ca18a6 100644 --- a/arch/mips/mm/page-funcs.S +++ b/arch/mips/mm/page-funcs.S @@ -8,8 +8,8 @@ * Copyright (C) 2012 MIPS Technologies, Inc. * Copyright (C) 2012 Ralf Baechle */ +#include #include -#include #include #ifdef CONFIG_SIBYTE_DMA_PAGEOPS diff --git a/arch/mips/mm/tlb-funcs.S b/arch/mips/mm/tlb-funcs.S index 00fef578c8cdc..2705d7dcb33ea 100644 --- a/arch/mips/mm/tlb-funcs.S +++ b/arch/mips/mm/tlb-funcs.S @@ -11,8 +11,8 @@ * Copyright (C) 2012 MIPS Technologies, Inc. * Copyright (C) 2012 Ralf Baechle */ +#include #include -#include #include #define FASTPATH_SIZE 128 -- GitLab From 0eefa56435299fb867fe6975cdf9c908b9c2ff8f Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 8 Aug 2023 00:32:43 +0900 Subject: [PATCH 1076/3445] mips: remove MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All *.S files under arch/mips/ have been converted to include instead of . Remove . Signed-off-by: Masahiro Yamada Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Bogendoerfer --- arch/mips/include/asm/Kbuild | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/include/asm/Kbuild b/arch/mips/include/asm/Kbuild index dee1727165817..7ba67a0d6c97b 100644 --- a/arch/mips/include/asm/Kbuild +++ b/arch/mips/include/asm/Kbuild @@ -7,7 +7,6 @@ generated-y += unistd_nr_n32.h generated-y += unistd_nr_n64.h generated-y += unistd_nr_o32.h -generic-y += export.h generic-y += kvm_para.h generic-y += mcs_spinlock.h generic-y += parport.h -- GitLab From ed07f6c26f9c18e5122ecba0526923ba32a7a6f7 Mon Sep 17 00:00:00 2001 From: Sui Jingfeng Date: Thu, 3 Aug 2023 17:16:37 +0800 Subject: [PATCH 1077/3445] Mips: loongson3_defconfig: Enable ast drm driver by default ASpeed GPU is typically found on the Loongson server platform, as a peripheral device driver, it generally should be compiled as a module. Tested on loongson 3B4000 server[1]. [1] https://github.com/loongson-gfx/loongson_boards/tree/main/ls3b4000x2_server Signed-off-by: Sui Jingfeng Signed-off-by: Thomas Bogendoerfer --- arch/mips/configs/loongson3_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/configs/loongson3_defconfig b/arch/mips/configs/loongson3_defconfig index 3087e64e6ebe7..a9fadea72da5d 100644 --- a/arch/mips/configs/loongson3_defconfig +++ b/arch/mips/configs/loongson3_defconfig @@ -283,6 +283,7 @@ CONFIG_DRM_AMDGPU_USERPTR=y CONFIG_DRM_AMD_ACP=y CONFIG_DRM_AMD_DC=y CONFIG_DRM_AMD_DC_SI=y +CONFIG_DRM_AST=m CONFIG_DRM_RADEON=m CONFIG_DRM_QXL=y CONFIG_DRM_VIRTIO_GPU=y -- GitLab From 179507fcd5e448eaecae9b69f0fb30965c3c4466 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 9 Aug 2023 14:53:14 +0200 Subject: [PATCH 1078/3445] leds: pca995x: Fix MODULE_DEVICE_TABLE for OF Fix copy-paste error in MODULE_DEVICE_TABLE() for the OF table, use the 'of' first parameter instead of duplicate 'i2c'. Fixes: ee4e80b2962e ("leds: pca995x: Add support for PCA995X chips") Signed-off-by: Marek Vasut Link: https://lore.kernel.org/r/20230809125314.531806-1-marex@denx.de Signed-off-by: Lee Jones --- drivers/leds/leds-pca995x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/leds-pca995x.c b/drivers/leds/leds-pca995x.c index 3ac99a433fcd2..78215dff14997 100644 --- a/drivers/leds/leds-pca995x.c +++ b/drivers/leds/leds-pca995x.c @@ -187,7 +187,7 @@ static const struct of_device_id pca995x_of_match[] = { { .compatible = "nxp,pca9955b", .data = (void *)PCA995X_TYPE_B }, {}, }; -MODULE_DEVICE_TABLE(i2c, pca995x_of_match); +MODULE_DEVICE_TABLE(of, pca995x_of_match); static struct i2c_driver pca995x_driver = { .driver = { -- GitLab From 07b4c950f27bef0362dc6ad7ee713aab61d58149 Mon Sep 17 00:00:00 2001 From: Felix Engelhardt Date: Tue, 15 Aug 2023 11:37:48 -0700 Subject: [PATCH 1079/3445] Input: goodix - add support for ACPI ID GDX9110 The Goodix touchscreen controller with ACPI ID GDX9110 was not recognized by the goodix driver. This patch adds this ID to the list of supported IDs, allowing the driver to be used with this device. The change will allow Linux to be used on ~1 million tablet devices used in Kenyan primary schools. Signed-off-by: Felix Engelhardt Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20230807124723.382899-1-felix.engelhardt@eidu.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/goodix.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index f5aa240739f97..7f5cfc5e136ea 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -1517,6 +1517,7 @@ MODULE_DEVICE_TABLE(i2c, goodix_ts_id); static const struct acpi_device_id goodix_acpi_match[] = { { "GDIX1001", 0 }, { "GDIX1002", 0 }, + { "GDX9110", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, goodix_acpi_match); -- GitLab From 0a30e59f22b207f2ed415daa44cfc0533adc329e Mon Sep 17 00:00:00 2001 From: Saravanan Vajravel Date: Mon, 31 Jul 2023 01:01:13 -0700 Subject: [PATCH 1080/3445] RDMA/bnxt_re: Add support for dmabuf pinned memory regions Support the new verb which indicates dmabuf support. bnxt doesn't support ODP. So use the pinned version of the dmabuf APIs to enable bnxt_re devices to work as dmabuf importer. Link: https://lore.kernel.org/r/1690790473-25850-2-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Saravanan Vajravel Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 83 ++++++++++++++++-------- drivers/infiniband/hw/bnxt_re/ib_verbs.h | 4 ++ drivers/infiniband/hw/bnxt_re/main.c | 1 + 3 files changed, 62 insertions(+), 26 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index b19334ce93c33..34c806a622698 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -3974,16 +3974,13 @@ int bnxt_re_dealloc_mw(struct ib_mw *ib_mw) return rc; } -/* uverbs */ -struct ib_mr *bnxt_re_reg_user_mr(struct ib_pd *ib_pd, u64 start, u64 length, - u64 virt_addr, int mr_access_flags, - struct ib_udata *udata) +static struct ib_mr *__bnxt_re_user_reg_mr(struct ib_pd *ib_pd, u64 length, u64 virt_addr, + int mr_access_flags, struct ib_umem *umem) { struct bnxt_re_pd *pd = container_of(ib_pd, struct bnxt_re_pd, ib_pd); struct bnxt_re_dev *rdev = pd->rdev; - struct bnxt_re_mr *mr; - struct ib_umem *umem; unsigned long page_size; + struct bnxt_re_mr *mr; int umem_pgs, rc; u32 active_mrs; @@ -3993,6 +3990,12 @@ struct ib_mr *bnxt_re_reg_user_mr(struct ib_pd *ib_pd, u64 start, u64 length, return ERR_PTR(-ENOMEM); } + page_size = ib_umem_find_best_pgsz(umem, BNXT_RE_PAGE_SIZE_SUPPORTED, virt_addr); + if (!page_size) { + ibdev_err(&rdev->ibdev, "umem page size unsupported!"); + return ERR_PTR(-EINVAL); + } + mr = kzalloc(sizeof(*mr), GFP_KERNEL); if (!mr) return ERR_PTR(-ENOMEM); @@ -4004,36 +4007,23 @@ struct ib_mr *bnxt_re_reg_user_mr(struct ib_pd *ib_pd, u64 start, u64 length, rc = bnxt_qplib_alloc_mrw(&rdev->qplib_res, &mr->qplib_mr); if (rc) { - ibdev_err(&rdev->ibdev, "Failed to allocate MR"); + ibdev_err(&rdev->ibdev, "Failed to allocate MR rc = %d", rc); + rc = -EIO; goto free_mr; } /* The fixed portion of the rkey is the same as the lkey */ mr->ib_mr.rkey = mr->qplib_mr.rkey; - - umem = ib_umem_get(&rdev->ibdev, start, length, mr_access_flags); - if (IS_ERR(umem)) { - ibdev_err(&rdev->ibdev, "Failed to get umem"); - rc = -EFAULT; - goto free_mrw; - } mr->ib_umem = umem; - mr->qplib_mr.va = virt_addr; - page_size = ib_umem_find_best_pgsz( - umem, BNXT_RE_PAGE_SIZE_SUPPORTED, virt_addr); - if (!page_size) { - ibdev_err(&rdev->ibdev, "umem page size unsupported!"); - rc = -EFAULT; - goto free_umem; - } mr->qplib_mr.total_size = length; umem_pgs = ib_umem_num_dma_blocks(umem, page_size); rc = bnxt_qplib_reg_mr(&rdev->qplib_res, &mr->qplib_mr, umem, umem_pgs, page_size); if (rc) { - ibdev_err(&rdev->ibdev, "Failed to register user MR"); - goto free_umem; + ibdev_err(&rdev->ibdev, "Failed to register user MR - rc = %d\n", rc); + rc = -EIO; + goto free_mrw; } mr->ib_mr.lkey = mr->qplib_mr.lkey; @@ -4043,8 +4033,7 @@ struct ib_mr *bnxt_re_reg_user_mr(struct ib_pd *ib_pd, u64 start, u64 length, rdev->stats.res.mr_watermark = active_mrs; return &mr->ib_mr; -free_umem: - ib_umem_release(umem); + free_mrw: bnxt_qplib_free_mrw(&rdev->qplib_res, &mr->qplib_mr); free_mr: @@ -4052,6 +4041,48 @@ free_mr: return ERR_PTR(rc); } +struct ib_mr *bnxt_re_reg_user_mr(struct ib_pd *ib_pd, u64 start, u64 length, + u64 virt_addr, int mr_access_flags, + struct ib_udata *udata) +{ + struct bnxt_re_pd *pd = container_of(ib_pd, struct bnxt_re_pd, ib_pd); + struct bnxt_re_dev *rdev = pd->rdev; + struct ib_umem *umem; + struct ib_mr *ib_mr; + + umem = ib_umem_get(&rdev->ibdev, start, length, mr_access_flags); + if (IS_ERR(umem)) + return ERR_CAST(umem); + + ib_mr = __bnxt_re_user_reg_mr(ib_pd, length, virt_addr, mr_access_flags, umem); + if (IS_ERR(ib_mr)) + ib_umem_release(umem); + return ib_mr; +} + +struct ib_mr *bnxt_re_reg_user_mr_dmabuf(struct ib_pd *ib_pd, u64 start, + u64 length, u64 virt_addr, int fd, + int mr_access_flags, struct ib_udata *udata) +{ + struct bnxt_re_pd *pd = container_of(ib_pd, struct bnxt_re_pd, ib_pd); + struct bnxt_re_dev *rdev = pd->rdev; + struct ib_umem_dmabuf *umem_dmabuf; + struct ib_umem *umem; + struct ib_mr *ib_mr; + + umem_dmabuf = ib_umem_dmabuf_get_pinned(&rdev->ibdev, start, length, + fd, mr_access_flags); + if (IS_ERR(umem_dmabuf)) + return ERR_CAST(umem_dmabuf); + + umem = &umem_dmabuf->umem; + + ib_mr = __bnxt_re_user_reg_mr(ib_pd, length, virt_addr, mr_access_flags, umem); + if (IS_ERR(ib_mr)) + ib_umem_release(umem); + return ib_mr; +} + int bnxt_re_alloc_ucontext(struct ib_ucontext *ctx, struct ib_udata *udata) { struct ib_device *ibdev = ctx->device; diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.h b/drivers/infiniband/hw/bnxt_re/ib_verbs.h index f392a09b9e2c1..84715b7e7a4e4 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.h +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.h @@ -229,6 +229,10 @@ int bnxt_re_dealloc_mw(struct ib_mw *mw); struct ib_mr *bnxt_re_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt_addr, int mr_access_flags, struct ib_udata *udata); +struct ib_mr *bnxt_re_reg_user_mr_dmabuf(struct ib_pd *ib_pd, u64 start, + u64 length, u64 virt_addr, + int fd, int mr_access_flags, + struct ib_udata *udata); int bnxt_re_alloc_ucontext(struct ib_ucontext *ctx, struct ib_udata *udata); void bnxt_re_dealloc_ucontext(struct ib_ucontext *context); int bnxt_re_mmap(struct ib_ucontext *context, struct vm_area_struct *vma); diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index 061a89bbb3b0d..8654ff9744a17 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -861,6 +861,7 @@ static const struct ib_device_ops bnxt_re_dev_ops = { .query_qp = bnxt_re_query_qp, .query_srq = bnxt_re_query_srq, .reg_user_mr = bnxt_re_reg_user_mr, + .reg_user_mr_dmabuf = bnxt_re_reg_user_mr_dmabuf, .req_notify_cq = bnxt_re_req_notify_cq, .resize_cq = bnxt_re_resize_cq, INIT_RDMA_OBJ_SIZE(ib_ah, bnxt_re_ah, ib_ah), -- GitLab From a6b33d009fc1fe80c935f18b714b36c81e1f1400 Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Mon, 14 Aug 2023 22:06:36 +0800 Subject: [PATCH 1081/3445] KVM: arm64: Remove unused declarations Commit 53692908b0f5 ("KVM: arm/arm64: vgic: Fix source vcpu issues for GICv2 SGI") removed vgic_v2_set_npie()/vgic_v3_set_npie() but not the declarations. Commit 29eb5a3c57f7 ("KVM: arm64: Handle PtrAuth traps early") left behind kvm_arm_vcpu_ptrauth_trap(), remove it. Commit 2a0c343386ae ("KVM: arm64: Initialize trap registers for protected VMs") declared but never implemented kvm_init_protected_traps() and commit cf5d318865e2 ("arm/arm64: KVM: Turn off vcpus on PSCI shutdown/reboot") declared but never implemented force_vm_exit(). Signed-off-by: Yue Haibing Reviewed-by: Zenghui Yu Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20230814140636.45988-1-yuehaibing@huawei.com --- arch/arm64/include/asm/kvm_host.h | 6 ------ arch/arm64/kvm/vgic/vgic.h | 2 -- 2 files changed, 8 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index d3dd05bbfe23f..d1a40fa26369b 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -967,8 +967,6 @@ void kvm_arm_resume_guest(struct kvm *kvm); #define kvm_call_hyp_nvhe(f, ...) f(__VA_ARGS__) #endif /* __KVM_NVHE_HYPERVISOR__ */ -void force_vm_exit(const cpumask_t *mask); - int handle_exit(struct kvm_vcpu *vcpu, int exception_index); void handle_exit_early(struct kvm_vcpu *vcpu, int exception_index); @@ -1049,8 +1047,6 @@ static inline bool kvm_system_needs_idmapped_vectors(void) return cpus_have_const_cap(ARM64_SPECTRE_V3A); } -void kvm_arm_vcpu_ptrauth_trap(struct kvm_vcpu *vcpu); - static inline void kvm_arch_sync_events(struct kvm *kvm) {} static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} @@ -1118,8 +1114,6 @@ static inline bool kvm_vm_is_protected(struct kvm *kvm) return false; } -void kvm_init_protected_traps(struct kvm_vcpu *vcpu); - int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature); bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu); diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h index f9923beedd276..0ab09b0d44404 100644 --- a/arch/arm64/kvm/vgic/vgic.h +++ b/arch/arm64/kvm/vgic/vgic.h @@ -199,7 +199,6 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu); void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr); void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr); void vgic_v2_set_underflow(struct kvm_vcpu *vcpu); -void vgic_v2_set_npie(struct kvm_vcpu *vcpu); int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr); int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write, int offset, u32 *val); @@ -233,7 +232,6 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu); void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr); void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr); void vgic_v3_set_underflow(struct kvm_vcpu *vcpu); -void vgic_v3_set_npie(struct kvm_vcpu *vcpu); void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr); void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr); void vgic_v3_enable(struct kvm_vcpu *vcpu); -- GitLab From 7777ac3dfe29f55dd0323d05a4cc81164fcfeb0e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 15 Aug 2023 16:30:56 -0300 Subject: [PATCH 1082/3445] perf test trace+probe_vfs_getname.sh: Remove stray \ before / Running on fedora:38 in verbose mode I noticed: # perf test -v 117 grep: warning: stray \ before / 117: Check open filename arg using perf trace + vfs_getname : Remove that \ before /. Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/ZNvTDsSMO3nw9Tnp@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/trace+probe_vfs_getname.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/tests/shell/trace+probe_vfs_getname.sh b/tools/perf/tests/shell/trace+probe_vfs_getname.sh index db2ff141f7037..3697f054ce190 100755 --- a/tools/perf/tests/shell/trace+probe_vfs_getname.sh +++ b/tools/perf/tests/shell/trace+probe_vfs_getname.sh @@ -20,7 +20,7 @@ skip_if_no_perf_trace || exit 2 trace_open_vfs_getname() { evts="$(echo "$(perf list syscalls:sys_enter_open* 2>/dev/null | grep -E 'open(at)? ' | sed -r 's/.*sys_enter_([a-z]+) +\[.*$/\1/')" | sed ':a;N;s:\n:,:g')" perf trace -e $evts touch $file 2>&1 | \ - grep -E " +[0-9]+\.[0-9]+ +\( +[0-9]+\.[0-9]+ ms\): +touch\/[0-9]+ open(at)?\((dfd: +CWD, +)?filename: +${file}, +flags: CREAT\|NOCTTY\|NONBLOCK\|WRONLY, +mode: +IRUGO\|IWUGO\) += +[0-9]+$" + grep -E " +[0-9]+\.[0-9]+ +\( +[0-9]+\.[0-9]+ ms\): +touch/[0-9]+ open(at)?\((dfd: +CWD, +)?filename: +${file}, +flags: CREAT\|NOCTTY\|NONBLOCK\|WRONLY, +mode: +IRUGO\|IWUGO\) += +[0-9]+$" } -- GitLab From 6f769c3458b6cf2ddb3537c2a0b17463ead2af87 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 15 Aug 2023 16:35:19 -0300 Subject: [PATCH 1083/3445] perf tests trace+probe_vfs_getname.sh: Accept quotes surrounding the filename With augmented_raw_syscalls transformed into a BPF skel made the output have a " around the filenames, which is not what the old perf probe vfs_getname method of obtaining filenames did, so accept the augmented way, with the quotes. At this point probably removing all the logic for the vfs_getname method is in order, will do it at some point. For now lets accept with/without quotes and make that test pass. Cc: Adrian Hunter Cc: Ian Rogers Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/lkml/ Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/trace+probe_vfs_getname.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/tests/shell/trace+probe_vfs_getname.sh b/tools/perf/tests/shell/trace+probe_vfs_getname.sh index 3697f054ce190..4014487cf4d93 100755 --- a/tools/perf/tests/shell/trace+probe_vfs_getname.sh +++ b/tools/perf/tests/shell/trace+probe_vfs_getname.sh @@ -20,7 +20,7 @@ skip_if_no_perf_trace || exit 2 trace_open_vfs_getname() { evts="$(echo "$(perf list syscalls:sys_enter_open* 2>/dev/null | grep -E 'open(at)? ' | sed -r 's/.*sys_enter_([a-z]+) +\[.*$/\1/')" | sed ':a;N;s:\n:,:g')" perf trace -e $evts touch $file 2>&1 | \ - grep -E " +[0-9]+\.[0-9]+ +\( +[0-9]+\.[0-9]+ ms\): +touch/[0-9]+ open(at)?\((dfd: +CWD, +)?filename: +${file}, +flags: CREAT\|NOCTTY\|NONBLOCK\|WRONLY, +mode: +IRUGO\|IWUGO\) += +[0-9]+$" + grep -E " +[0-9]+\.[0-9]+ +\( +[0-9]+\.[0-9]+ ms\): +touch/[0-9]+ open(at)?\((dfd: +CWD, +)?filename: +\"?${file}\"?, +flags: CREAT\|NOCTTY\|NONBLOCK\|WRONLY, +mode: +IRUGO\|IWUGO\) += +[0-9]+$" } -- GitLab From 56b11a2126bf2f422831ecf6112b87a4485b221b Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 11 Aug 2023 12:19:48 -0300 Subject: [PATCH 1084/3445] perf bpf: Remove support for embedding clang for compiling BPF events (-e foo.c) This never was in the default build for perf, is difficult to maintain as it uses clang/llvm internals so ditch it, keeping, for now, the external compilation of .c BPF into .o bytecode and its subsequent loading, that is also going to be removed, do it separately to help bisection and to properly document what is being removed and why. Committer notes: Extracted from a larger patch and removed some leftovers, namely deleting these now unused feature tests: tools/build/feature/test-clang.cpp tools/build/feature/test-cxx.cpp tools/build/feature/test-llvm-version.cpp tools/build/feature/test-llvm.cpp Testing the use of BPF events after applying this patch: To use the external clang/llvm toolchain to compile a .c event and then use libbpf to load it, to get the syscalls:sys_enter_open* tracepoints and read the filename pointer, putting it into the ring buffer right after the usual tracepoint payload for 'perf trace' to then print it: [root@quaco ~]# perf trace -e /home/acme/git/perf-tools-next/tools/perf/examples/bpf/augmented_raw_syscalls.c,open* --max-events=10 0.000 systemd-oomd/959 openat(dfd: CWD, filename: "/proc/meminfo", flags: RDONLY|CLOEXEC) = 12 0.083 abrt-dump-jour/1453 openat(dfd: CWD, filename: "/var/log/journal/d6a97235307247e09f13f326fb607e3c/system.journal", flags: RDONLY|CLOEXEC|NONBLOCK) = 4 0.063 abrt-dump-jour/1454 openat(dfd: CWD, filename: "/var/log/journal/d6a97235307247e09f13f326fb607e3c/system.journal", flags: RDONLY|CLOEXEC|NONBLOCK) = 4 0.082 abrt-dump-jour/1455 openat(dfd: CWD, filename: "/var/log/journal/d6a97235307247e09f13f326fb607e3c/system.journal", flags: RDONLY|CLOEXEC|NONBLOCK) = 4 250.124 systemd-oomd/959 openat(dfd: CWD, filename: "/proc/meminfo", flags: RDONLY|CLOEXEC) = 12 250.521 systemd-oomd/959 openat(dfd: CWD, filename: "/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/app.slice/memory.pressure", flags: RDONLY|CLOEXEC) = 12 251.047 systemd-oomd/959 openat(dfd: CWD, filename: "/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/app.slice/memory.current", flags: RDONLY|CLOEXEC) = 12 251.162 systemd-oomd/959 openat(dfd: CWD, filename: "/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/app.slice/memory.min", flags: RDONLY|CLOEXEC) = 12 251.242 systemd-oomd/959 openat(dfd: CWD, filename: "/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/app.slice/memory.low", flags: RDONLY|CLOEXEC) = 12 251.353 systemd-oomd/959 openat(dfd: CWD, filename: "/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/app.slice/memory.swap.current", flags: RDONLY|CLOEXEC) = 12 [root@quaco ~]# Same thing, but with a prebuilt .o BPF bytecode: [root@quaco ~]# perf trace -e /home/acme/git/perf-tools-next/tools/perf/examples/bpf/augmented_raw_syscalls.o,open* --max-events=10 0.000 systemd-oomd/959 openat(dfd: CWD, filename: "/proc/meminfo", flags: RDONLY|CLOEXEC) = 12 0.083 abrt-dump-jour/1453 openat(dfd: CWD, filename: "/var/log/journal/d6a97235307247e09f13f326fb607e3c/system.journal", flags: RDONLY|CLOEXEC|NONBLOCK) = 4 0.083 abrt-dump-jour/1455 openat(dfd: CWD, filename: "/var/log/journal/d6a97235307247e09f13f326fb607e3c/system.journal", flags: RDONLY|CLOEXEC|NONBLOCK) = 4 0.062 abrt-dump-jour/1454 openat(dfd: CWD, filename: "/var/log/journal/d6a97235307247e09f13f326fb607e3c/system.journal", flags: RDONLY|CLOEXEC|NONBLOCK) = 4 249.985 systemd-oomd/959 openat(dfd: CWD, filename: "/proc/meminfo", flags: RDONLY|CLOEXEC) = 12 466.763 thermald/1234 openat(dfd: CWD, filename: "/sys/class/powercap/intel-rapl/intel-rapl:0/intel-rapl:0:2/energy_uj") = 13 467.145 thermald/1234 openat(dfd: CWD, filename: "/sys/class/powercap/intel-rapl/intel-rapl:0/energy_uj") = 13 467.311 thermald/1234 openat(dfd: CWD, filename: "/sys/class/thermal/thermal_zone2/temp") = 13 500.040 cgroupify/24006 openat(dfd: 4, filename: ".", flags: RDONLY|CLOEXEC|DIRECTORY|NONBLOCK) = 5 500.295 cgroupify/24006 openat(dfd: 4, filename: "24616/cgroup.procs") = 5 [root@quaco ~]# Signed-off-by: Ian Rogers Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Andrii Nakryiko Cc: Anshuman Khandual Cc: Athira Rajeev Cc: Brendan Gregg Cc: Carsten Haitzler Cc: Eduard Zingerman Cc: Fangrui Song Cc: He Kuang Cc: Ingo Molnar Cc: James Clark Cc: Jiri Olsa Cc: Kan Liang Cc: Leo Yan Cc: Madhavan Srinivasan Cc: Mark Rutland Cc: Namhyung Kim Cc: Nathan Chancellor Cc: "Naveen N. Rao" Cc: Nick Desaulniers Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Rob Herring Cc: Tiezhu Yang Cc: Tom Rix Cc: Wang Nan Cc: Wang ShaoBo Cc: Yang Jihong Cc: Yonghong Song Cc: YueHaibing Link: https://lore.kernel.org/lkml/ZNZWsAXg2px1sm2h@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/feature/test-clang.cpp | 28 --- tools/build/feature/test-cxx.cpp | 16 -- tools/build/feature/test-llvm-version.cpp | 12 -- tools/build/feature/test-llvm.cpp | 14 -- tools/perf/Makefile.config | 31 --- tools/perf/Makefile.perf | 17 -- tools/perf/tests/Build | 1 - tools/perf/tests/builtin-test.c | 1 - tools/perf/tests/clang.c | 32 --- tools/perf/tests/make | 1 - tools/perf/util/Build | 2 - tools/perf/util/bpf-loader.c | 15 +- tools/perf/util/c++/Build | 5 - tools/perf/util/c++/clang-c.h | 43 ----- tools/perf/util/c++/clang-test.cpp | 67 ------- tools/perf/util/c++/clang.cpp | 225 ---------------------- tools/perf/util/c++/clang.h | 27 --- 17 files changed, 4 insertions(+), 533 deletions(-) delete mode 100644 tools/build/feature/test-clang.cpp delete mode 100644 tools/build/feature/test-cxx.cpp delete mode 100644 tools/build/feature/test-llvm-version.cpp delete mode 100644 tools/build/feature/test-llvm.cpp delete mode 100644 tools/perf/tests/clang.c delete mode 100644 tools/perf/util/c++/Build delete mode 100644 tools/perf/util/c++/clang-c.h delete mode 100644 tools/perf/util/c++/clang-test.cpp delete mode 100644 tools/perf/util/c++/clang.cpp delete mode 100644 tools/perf/util/c++/clang.h diff --git a/tools/build/feature/test-clang.cpp b/tools/build/feature/test-clang.cpp deleted file mode 100644 index 7d87075cd1c5d..0000000000000 --- a/tools/build/feature/test-clang.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include "clang/Basic/Version.h" -#if CLANG_VERSION_MAJOR < 8 -#include "clang/Basic/VirtualFileSystem.h" -#endif -#include "clang/Driver/Driver.h" -#include "clang/Frontend/TextDiagnosticPrinter.h" -#include "llvm/ADT/IntrusiveRefCntPtr.h" -#include "llvm/Support/ManagedStatic.h" -#if CLANG_VERSION_MAJOR >= 8 -#include "llvm/Support/VirtualFileSystem.h" -#endif -#include "llvm/Support/raw_ostream.h" - -using namespace clang; -using namespace clang::driver; - -int main() -{ - IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); - IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); - - DiagnosticsEngine Diags(DiagID, &*DiagOpts); - Driver TheDriver("test", "bpf-pc-linux", Diags); - - llvm::llvm_shutdown(); - return 0; -} diff --git a/tools/build/feature/test-cxx.cpp b/tools/build/feature/test-cxx.cpp deleted file mode 100644 index 396aaedd2418d..0000000000000 --- a/tools/build/feature/test-cxx.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - -static void print_str(std::string s) -{ - std::cout << s << std::endl; -} - -int main() -{ - std::string s("Hello World!"); - print_str(std::move(s)); - std::cout << "|" << s << "|" << std::endl; - return 0; -} diff --git a/tools/build/feature/test-llvm-version.cpp b/tools/build/feature/test-llvm-version.cpp deleted file mode 100644 index 8a091625446af..0000000000000 --- a/tools/build/feature/test-llvm-version.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include "llvm/Config/llvm-config.h" - -#define NUM_VERSION (((LLVM_VERSION_MAJOR) << 16) + (LLVM_VERSION_MINOR << 8) + LLVM_VERSION_PATCH) -#define pass int main() {printf("%x\n", NUM_VERSION); return 0;} - -#if NUM_VERSION >= 0x030900 -pass -#else -# error This LLVM is not tested yet. -#endif diff --git a/tools/build/feature/test-llvm.cpp b/tools/build/feature/test-llvm.cpp deleted file mode 100644 index 88a3d1bdd9f69..0000000000000 --- a/tools/build/feature/test-llvm.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/raw_ostream.h" -#define NUM_VERSION (((LLVM_VERSION_MAJOR) << 16) + (LLVM_VERSION_MINOR << 8) + LLVM_VERSION_PATCH) - -#if NUM_VERSION < 0x030900 -# error "LLVM version too low" -#endif -int main() -{ - llvm::errs() << "Hello World!\n"; - llvm::llvm_shutdown(); - return 0; -} diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 1bf8dc53641fa..e0592ed4c10f5 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -1127,37 +1127,6 @@ ifndef NO_JVMTI endif endif -USE_CXX = 0 -USE_CLANGLLVM = 0 -ifdef LIBCLANGLLVM - $(call feature_check,cxx) - ifneq ($(feature-cxx), 1) - msg := $(warning No g++ found, disable clang and llvm support. Please install g++) - else - $(call feature_check,llvm) - $(call feature_check,llvm-version) - ifneq ($(feature-llvm), 1) - msg := $(warning No suitable libLLVM found, disabling builtin clang and LLVM support. Please install llvm-dev(el) (>= 3.9.0)) - else - $(call feature_check,clang) - ifneq ($(feature-clang), 1) - msg := $(warning No suitable libclang found, disabling builtin clang and LLVM support. Please install libclang-dev(el) (>= 3.9.0)) - else - CFLAGS += -DHAVE_LIBCLANGLLVM_SUPPORT - CXXFLAGS += -DHAVE_LIBCLANGLLVM_SUPPORT -I$(shell $(LLVM_CONFIG) --includedir) - $(call detected,CONFIG_CXX) - $(call detected,CONFIG_CLANGLLVM) - USE_CXX = 1 - USE_LLVM = 1 - USE_CLANG = 1 - ifneq ($(feature-llvm-version),1) - msg := $(warning This version of LLVM is not tested. May cause build errors) - endif - endif - endif - endif -endif - ifndef NO_LIBPFM4 $(call feature_check,libpfm4) ifeq ($(feature-libpfm4), 1) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 0ed7ee0c1665a..5370d7bf123e7 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -99,10 +99,6 @@ include ../scripts/utilities.mak # Define NO_JVMTI_CMLR (debug only) if you do not want to process CMLR # data for java source lines. # -# Define LIBCLANGLLVM if you DO want builtin clang and llvm support. -# When selected, pass LLVM_CONFIG=/path/to/llvm-config to `make' if -# llvm-config is not in $PATH. -# # Define CORESIGHT if you DO WANT support for CoreSight trace decoding. # # Define NO_AIO if you do not want support of Posix AIO based trace @@ -425,19 +421,6 @@ endif EXTLIBS := $(call filter-out,$(EXCLUDE_EXTLIBS),$(EXTLIBS)) LIBS = -Wl,--whole-archive $(PERFLIBS) $(EXTRA_PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group -ifeq ($(USE_CLANG), 1) - LIBS += -L$(shell $(LLVM_CONFIG) --libdir) -lclang-cpp -endif - -ifeq ($(USE_LLVM), 1) - LIBLLVM = $(shell $(LLVM_CONFIG) --libs all) $(shell $(LLVM_CONFIG) --system-libs) - LIBS += -L$(shell $(LLVM_CONFIG) --libdir) $(LIBLLVM) -endif - -ifeq ($(USE_CXX), 1) - LIBS += -lstdc++ -endif - export INSTALL SHELL_PATH ### Build rules diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index fb9ac5dc4079d..52df5923a8b9c 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -51,7 +51,6 @@ perf-y += sdt.o perf-y += is_printable_array.o perf-y += bitmap.o perf-y += perf-hooks.o -perf-y += clang.o perf-y += unit_number__scnprintf.o perf-y += mem2node.o perf-y += maps.o diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 6accb5442a731..0f3691fd31c25 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -108,7 +108,6 @@ static struct test_suite *generic_tests[] = { &suite__is_printable_array, &suite__bitmap_print, &suite__perf_hooks, - &suite__clang, &suite__unit_number__scnprint, &suite__mem2node, &suite__time_utils, diff --git a/tools/perf/tests/clang.c b/tools/perf/tests/clang.c deleted file mode 100644 index a7111005d5b9f..0000000000000 --- a/tools/perf/tests/clang.c +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include "tests.h" -#include "c++/clang-c.h" -#include - -#ifndef HAVE_LIBCLANGLLVM_SUPPORT -static int test__clang_to_IR(struct test_suite *test __maybe_unused, - int subtest __maybe_unused) -{ - return TEST_SKIP; -} - -static int test__clang_to_obj(struct test_suite *test __maybe_unused, - int subtest __maybe_unused) -{ - return TEST_SKIP; -} -#endif - -static struct test_case clang_tests[] = { - TEST_CASE_REASON("builtin clang compile C source to IR", clang_to_IR, - "not compiled in"), - TEST_CASE_REASON("builtin clang compile C source to ELF object", - clang_to_obj, - "not compiled in"), - { .name = NULL, } -}; - -struct test_suite suite__clang = { - .desc = "builtin clang support", - .test_cases = clang_tests, -}; diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 58cf96d762d06..ea4c341f5af11 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -95,7 +95,6 @@ make_with_babeltrace:= LIBBABELTRACE=1 make_with_coresight := CORESIGHT=1 make_no_sdt := NO_SDT=1 make_no_syscall_tbl := NO_SYSCALL_TABLE=1 -make_with_clangllvm := LIBCLANGLLVM=1 make_no_libpfm4 := NO_LIBPFM4=1 make_with_gtk2 := GTK2=1 make_refcnt_check := EXTRA_CFLAGS="-DREFCNT_CHECKING=1" diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 9699e31ff4c04..ff3b55c7ed43c 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -232,8 +232,6 @@ perf-y += perf-hooks.o perf-$(CONFIG_LIBBPF) += bpf-event.o perf-$(CONFIG_LIBBPF) += bpf-utils.o -perf-$(CONFIG_CXX) += c++/ - perf-$(CONFIG_LIBPFM4) += pfm.o CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 50e42698cbb72..b54e42f17926b 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -26,7 +26,6 @@ #include "strfilter.h" #include "util.h" #include "llvm-utils.h" -#include "c++/clang-c.h" #include "util/hashmap.h" #include "asm/bug.h" @@ -220,16 +219,10 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source) void *obj_buf; size_t obj_buf_sz; - perf_clang__init(); - err = perf_clang__compile_bpf(filename, &obj_buf, &obj_buf_sz); - perf_clang__cleanup(); - if (err) { - pr_debug("bpf: builtin compilation failed: %d, try external compiler\n", err); - err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz); - if (err) - return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE); - } else - pr_debug("bpf: successful builtin compilation\n"); + err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz); + if (err) + return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE); + obj = bpf_object__open_mem(obj_buf, obj_buf_sz, &opts); if (!IS_ERR_OR_NULL(obj) && llvm_param.dump_obj) diff --git a/tools/perf/util/c++/Build b/tools/perf/util/c++/Build deleted file mode 100644 index 8610d032ac19d..0000000000000 --- a/tools/perf/util/c++/Build +++ /dev/null @@ -1,5 +0,0 @@ -perf-$(CONFIG_CLANGLLVM) += clang.o -perf-$(CONFIG_CLANGLLVM) += clang-test.o - -CXXFLAGS_clang.o += -Wno-unused-parameter -CXXFLAGS_clang-test.o += -Wno-unused-parameter diff --git a/tools/perf/util/c++/clang-c.h b/tools/perf/util/c++/clang-c.h deleted file mode 100644 index d3731a876b6c1..0000000000000 --- a/tools/perf/util/c++/clang-c.h +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef PERF_UTIL_CLANG_C_H -#define PERF_UTIL_CLANG_C_H - -#include /* for size_t */ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef HAVE_LIBCLANGLLVM_SUPPORT -extern void perf_clang__init(void); -extern void perf_clang__cleanup(void); - -struct test_suite; -extern int test__clang_to_IR(struct test_suite *test, int subtest); -extern int test__clang_to_obj(struct test_suite *test, int subtest); - -extern int perf_clang__compile_bpf(const char *filename, - void **p_obj_buf, - size_t *p_obj_buf_sz); -#else - -#include -#include /* for __maybe_unused */ - -static inline void perf_clang__init(void) { } -static inline void perf_clang__cleanup(void) { } - -static inline int -perf_clang__compile_bpf(const char *filename __maybe_unused, - void **p_obj_buf __maybe_unused, - size_t *p_obj_buf_sz __maybe_unused) -{ - return -ENOTSUP; -} - -#endif - -#ifdef __cplusplus -} -#endif -#endif diff --git a/tools/perf/util/c++/clang-test.cpp b/tools/perf/util/c++/clang-test.cpp deleted file mode 100644 index a4683ca536973..0000000000000 --- a/tools/perf/util/c++/clang-test.cpp +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include "clang.h" -#include "clang-c.h" -extern "C" { -#include "../util.h" -} -#include "llvm/IR/Function.h" -#include "llvm/IR/LLVMContext.h" - -#include -#include - -class perf_clang_scope { -public: - explicit perf_clang_scope() {perf_clang__init();} - ~perf_clang_scope() {perf_clang__cleanup();} -}; - -static std::unique_ptr -__test__clang_to_IR(void) -{ - unsigned int kernel_version; - - if (fetch_kernel_version(&kernel_version, NULL, 0)) - return std::unique_ptr(nullptr); - - std::string cflag_kver("-DLINUX_VERSION_CODE=" + - std::to_string(kernel_version)); - - std::unique_ptr M = - perf::getModuleFromSource({cflag_kver.c_str()}, - "perf-test.c", - test_llvm__bpf_base_prog); - return M; -} - -extern "C" { -int test__clang_to_IR(struct test_suite *test __maybe_unused, - int subtest __maybe_unused) -{ - perf_clang_scope _scope; - - auto M = __test__clang_to_IR(); - if (!M) - return -1; - for (llvm::Function& F : *M) - if (F.getName() == "bpf_func__SyS_epoll_pwait") - return 0; - return -1; -} - -int test__clang_to_obj(struct test_suite *test __maybe_unused, - int subtest __maybe_unused) -{ - perf_clang_scope _scope; - - auto M = __test__clang_to_IR(); - if (!M) - return -1; - - auto Buffer = perf::getBPFObjectFromModule(&*M); - if (!Buffer) - return -1; - return 0; -} - -} diff --git a/tools/perf/util/c++/clang.cpp b/tools/perf/util/c++/clang.cpp deleted file mode 100644 index 1aad7d6d34aaa..0000000000000 --- a/tools/perf/util/c++/clang.cpp +++ /dev/null @@ -1,225 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * llvm C frontend for perf. Support dynamically compile C file - * - * Inspired by clang example code: - * http://llvm.org/svn/llvm-project/cfe/trunk/examples/clang-interpreter/main.cpp - * - * Copyright (C) 2016 Wang Nan - * Copyright (C) 2016 Huawei Inc. - */ - -#include "clang/Basic/Version.h" -#include "clang/CodeGen/CodeGenAction.h" -#include "clang/Frontend/CompilerInvocation.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/TextDiagnosticPrinter.h" -#include "clang/Tooling/Tooling.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/Module.h" -#include "llvm/Option/Option.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/ManagedStatic.h" -#if CLANG_VERSION_MAJOR >= 14 -#include "llvm/MC/TargetRegistry.h" -#else -#include "llvm/Support/TargetRegistry.h" -#endif -#include "llvm/Support/TargetSelect.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetOptions.h" -#include - -#include "clang.h" -#include "clang-c.h" - -namespace perf { - -static std::unique_ptr LLVMCtx; - -using namespace clang; - -static CompilerInvocation * -createCompilerInvocation(llvm::opt::ArgStringList CFlags, StringRef& Path, - DiagnosticsEngine& Diags) -{ - llvm::opt::ArgStringList CCArgs { - "-cc1", - "-triple", "bpf-pc-linux", - "-fsyntax-only", - "-O2", - "-nostdsysteminc", - "-nobuiltininc", - "-vectorize-loops", - "-vectorize-slp", - "-Wno-unused-value", - "-Wno-pointer-sign", - "-x", "c"}; - - CCArgs.append(CFlags.begin(), CFlags.end()); - CompilerInvocation *CI = tooling::newInvocation(&Diags, CCArgs -#if CLANG_VERSION_MAJOR >= 11 - ,/*BinaryName=*/nullptr -#endif - ); - - FrontendOptions& Opts = CI->getFrontendOpts(); - Opts.Inputs.clear(); - Opts.Inputs.emplace_back(Path, - FrontendOptions::getInputKindForExtension("c")); - return CI; -} - -static std::unique_ptr -getModuleFromSource(llvm::opt::ArgStringList CFlags, - StringRef Path, IntrusiveRefCntPtr VFS) -{ - CompilerInstance Clang; - Clang.createDiagnostics(); - -#if CLANG_VERSION_MAJOR < 9 - Clang.setVirtualFileSystem(&*VFS); -#else - Clang.createFileManager(&*VFS); -#endif - -#if CLANG_VERSION_MAJOR < 4 - IntrusiveRefCntPtr CI = - createCompilerInvocation(std::move(CFlags), Path, - Clang.getDiagnostics()); - Clang.setInvocation(&*CI); -#else - std::shared_ptr CI( - createCompilerInvocation(std::move(CFlags), Path, - Clang.getDiagnostics())); - Clang.setInvocation(CI); -#endif - - std::unique_ptr Act(new EmitLLVMOnlyAction(&*LLVMCtx)); - if (!Clang.ExecuteAction(*Act)) - return std::unique_ptr(nullptr); - - return Act->takeModule(); -} - -std::unique_ptr -getModuleFromSource(llvm::opt::ArgStringList CFlags, - StringRef Name, StringRef Content) -{ - using namespace vfs; - - llvm::IntrusiveRefCntPtr OverlayFS( - new OverlayFileSystem(getRealFileSystem())); - llvm::IntrusiveRefCntPtr MemFS( - new InMemoryFileSystem(true)); - - /* - * pushOverlay helps setting working dir for MemFS. Must call - * before addFile. - */ - OverlayFS->pushOverlay(MemFS); - MemFS->addFile(Twine(Name), 0, llvm::MemoryBuffer::getMemBuffer(Content)); - - return getModuleFromSource(std::move(CFlags), Name, OverlayFS); -} - -std::unique_ptr -getModuleFromSource(llvm::opt::ArgStringList CFlags, StringRef Path) -{ - IntrusiveRefCntPtr VFS(vfs::getRealFileSystem()); - return getModuleFromSource(std::move(CFlags), Path, VFS); -} - -std::unique_ptr> -getBPFObjectFromModule(llvm::Module *Module) -{ - using namespace llvm; - - std::string TargetTriple("bpf-pc-linux"); - std::string Error; - const Target* Target = TargetRegistry::lookupTarget(TargetTriple, Error); - if (!Target) { - llvm::errs() << Error; - return std::unique_ptr>(nullptr); - } - - llvm::TargetOptions Opt; - TargetMachine *TargetMachine = - Target->createTargetMachine(TargetTriple, - "generic", "", - Opt, Reloc::Static); - - Module->setDataLayout(TargetMachine->createDataLayout()); - Module->setTargetTriple(TargetTriple); - - std::unique_ptr> Buffer(new SmallVector()); - raw_svector_ostream ostream(*Buffer); - - legacy::PassManager PM; - bool NotAdded; - NotAdded = TargetMachine->addPassesToEmitFile(PM, ostream -#if CLANG_VERSION_MAJOR >= 7 - , /*DwoOut=*/nullptr -#endif -#if CLANG_VERSION_MAJOR < 10 - , TargetMachine::CGFT_ObjectFile -#else - , llvm::CGFT_ObjectFile -#endif - ); - if (NotAdded) { - llvm::errs() << "TargetMachine can't emit a file of this type\n"; - return std::unique_ptr>(nullptr); - } - PM.run(*Module); - - return Buffer; -} - -} - -extern "C" { -void perf_clang__init(void) -{ - perf::LLVMCtx.reset(new llvm::LLVMContext()); - LLVMInitializeBPFTargetInfo(); - LLVMInitializeBPFTarget(); - LLVMInitializeBPFTargetMC(); - LLVMInitializeBPFAsmPrinter(); -} - -void perf_clang__cleanup(void) -{ - perf::LLVMCtx.reset(nullptr); - llvm::llvm_shutdown(); -} - -int perf_clang__compile_bpf(const char *filename, - void **p_obj_buf, - size_t *p_obj_buf_sz) -{ - using namespace perf; - - if (!p_obj_buf || !p_obj_buf_sz) - return -EINVAL; - - llvm::opt::ArgStringList CFlags; - auto M = getModuleFromSource(std::move(CFlags), filename); - if (!M) - return -EINVAL; - auto O = getBPFObjectFromModule(&*M); - if (!O) - return -EINVAL; - - size_t size = O->size_in_bytes(); - void *buffer; - - buffer = malloc(size); - if (!buffer) - return -ENOMEM; - memcpy(buffer, O->data(), size); - *p_obj_buf = buffer; - *p_obj_buf_sz = size; - return 0; -} -} diff --git a/tools/perf/util/c++/clang.h b/tools/perf/util/c++/clang.h deleted file mode 100644 index 6ce33e22f23c0..0000000000000 --- a/tools/perf/util/c++/clang.h +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef PERF_UTIL_CLANG_H -#define PERF_UTIL_CLANG_H - -#include "llvm/ADT/StringRef.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/Option/Option.h" -#include - -namespace perf { - -using namespace llvm; - -std::unique_ptr -getModuleFromSource(opt::ArgStringList CFlags, - StringRef Name, StringRef Content); - -std::unique_ptr -getModuleFromSource(opt::ArgStringList CFlags, - StringRef Path); - -std::unique_ptr> -getBPFObjectFromModule(llvm::Module *Module); - -} -#endif -- GitLab From 3d6dfae889174340af94c7357c8bae018966c524 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 11 Aug 2023 15:26:11 -0300 Subject: [PATCH 1085/3445] perf parse-events: Remove BPF event support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New features like the BPF --filter support in perf record have made the BPF event functionality somewhat redundant. As shown by commit fcb027c1a4f6 ("perf tools: Revert enable indices setting syntax for BPF map") and commit 14e4b9f4289a ("perf trace: Raw augmented syscalls fix libbpf 1.0+ compatibility") the BPF event support hasn't been well maintained and it adds considerable complexity in areas like event parsing, not least as '/' is a separator for event modifiers as well as in paths. This patch removes support in the event parser for BPF events and then the associated functions are removed. This leads to the removal of whole source files like bpf-loader.c. Removing support means that augmented syscalls in perf trace is broken, this will be fixed in a later commit adding support using BPF skeletons. The removal of BPF events causes an unused label warning from flex generated code, so update build to ignore it: ``` util/parse-events-flex.c:2704:1: error: label ‘find_rule’ defined but not used [-Werror=unused-label] 2704 | find_rule: /* we branch to this label when backing up */ ``` Committer notes: Extracted from a larger patch that was also removing the support for linking with libllvm and libclang, that were an alternative to using an external clang execution to compile the .c event source code into BPF bytecode. Testing it: # perf trace -e /home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.c event syntax error: '/home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.c' \___ Bad event or PMU Unabled to find PMU or event on a PMU of 'home' Initial error: event syntax error: '/home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.c' \___ Cannot find PMU `home'. Missing kernel support? Run 'perf list' for a list of valid events Usage: perf trace [] [] or: perf trace [] -- [] or: perf trace record [] [] or: perf trace record [] -- [] -e, --event event/syscall selector. use 'perf list' to list available events # Signed-off-by: Ian Rogers Acked-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Andrii Nakryiko Cc: Anshuman Khandual Cc: Athira Rajeev Cc: Brendan Gregg Cc: Carsten Haitzler Cc: Eduard Zingerman Cc: Fangrui Song Cc: He Kuang Cc: Ingo Molnar Cc: James Clark Cc: Kan Liang Cc: Leo Yan Cc: Madhavan Srinivasan Cc: Mark Rutland Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Naveen N. Rao Cc: Nick Desaulniers Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Rob Herring Cc: Tiezhu Yang Cc: Tom Rix Cc: Wang Nan Cc: Wang ShaoBo Cc: Yang Jihong Cc: Yonghong Song Cc: YueHaibing Cc: bpf@vger.kernel.org Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230810184853.2860737-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-config.txt | 33 - tools/perf/Documentation/perf-record.txt | 22 - tools/perf/Makefile.config | 12 - tools/perf/builtin-record.c | 45 - tools/perf/builtin-trace.c | 146 +- tools/perf/perf.c | 2 - tools/perf/tests/.gitignore | 5 - tools/perf/tests/Build | 30 - tools/perf/tests/bpf-script-example.c | 60 - tools/perf/tests/bpf-script-test-kbuild.c | 21 - tools/perf/tests/bpf-script-test-prologue.c | 49 - tools/perf/tests/bpf-script-test-relocation.c | 51 - tools/perf/tests/bpf.c | 390 ---- tools/perf/tests/builtin-test.c | 2 - tools/perf/tests/llvm.c | 219 -- tools/perf/tests/llvm.h | 31 - tools/perf/tests/tests.h | 2 - tools/perf/util/Build | 6 +- tools/perf/util/bpf-loader.c | 1999 ----------------- tools/perf/util/bpf-loader.h | 216 -- tools/perf/util/config.c | 4 - tools/perf/util/llvm-utils.c | 612 ----- tools/perf/util/llvm-utils.h | 69 - tools/perf/util/parse-events.c | 268 --- tools/perf/util/parse-events.h | 15 - tools/perf/util/parse-events.l | 31 - tools/perf/util/parse-events.y | 44 +- 27 files changed, 3 insertions(+), 4381 deletions(-) delete mode 100644 tools/perf/tests/.gitignore delete mode 100644 tools/perf/tests/bpf-script-example.c delete mode 100644 tools/perf/tests/bpf-script-test-kbuild.c delete mode 100644 tools/perf/tests/bpf-script-test-prologue.c delete mode 100644 tools/perf/tests/bpf-script-test-relocation.c delete mode 100644 tools/perf/tests/bpf.c delete mode 100644 tools/perf/tests/llvm.c delete mode 100644 tools/perf/tests/llvm.h delete mode 100644 tools/perf/util/bpf-loader.c delete mode 100644 tools/perf/util/bpf-loader.h delete mode 100644 tools/perf/util/llvm-utils.c delete mode 100644 tools/perf/util/llvm-utils.h diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt index 1478068ad5dd4..0b4e79dbd3f68 100644 --- a/tools/perf/Documentation/perf-config.txt +++ b/tools/perf/Documentation/perf-config.txt @@ -125,9 +125,6 @@ Given a $HOME/.perfconfig like this: group = true skip-empty = true - [llvm] - dump-obj = true - clang-opt = -g You can hide source code of annotate feature setting the config to false with @@ -657,36 +654,6 @@ ftrace.*:: -F option is not specified. Possible values are 'function' and 'function_graph'. -llvm.*:: - llvm.clang-path:: - Path to clang. If omit, search it from $PATH. - - llvm.clang-bpf-cmd-template:: - Cmdline template. Below lines show its default value. Environment - variable is used to pass options. - "$CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS "\ - "-DLINUX_VERSION_CODE=$LINUX_VERSION_CODE " \ - "$CLANG_OPTIONS $PERF_BPF_INC_OPTIONS $KERNEL_INC_OPTIONS " \ - "-Wno-unused-value -Wno-pointer-sign " \ - "-working-directory $WORKING_DIR " \ - "-c \"$CLANG_SOURCE\" --target=bpf $CLANG_EMIT_LLVM -O2 -o - $LLVM_OPTIONS_PIPE" - - llvm.clang-opt:: - Options passed to clang. - - llvm.kbuild-dir:: - kbuild directory. If not set, use /lib/modules/`uname -r`/build. - If set to "" deliberately, skip kernel header auto-detector. - - llvm.kbuild-opts:: - Options passed to 'make' when detecting kernel header options. - - llvm.dump-obj:: - Enable perf dump BPF object files compiled by LLVM. - - llvm.opts:: - Options passed to llc. - samples.*:: samples.context:: diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 680396c56bd10..7d362407fb39e 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -99,20 +99,6 @@ OPTIONS If you want to profile write accesses in [0x1000~1008), just set 'mem:0x1000/8:w'. - - a BPF source file (ending in .c) or a precompiled object file (ending - in .o) selects one or more BPF events. - The BPF program can attach to various perf events based on the ELF section - names. - - When processing a '.c' file, perf searches an installed LLVM to compile it - into an object file first. Optional clang options can be passed via the - '--clang-opt' command line option, e.g.: - - perf record --clang-opt "-DLINUX_VERSION_CODE=0x50000" \ - -e tests/bpf-script-example.c - - Note: '--clang-opt' must be placed before '--event/-e'. - - a group of events surrounded by a pair of brace ("{event1,event2,...}"). Each event is separated by commas and the group should be quoted to prevent the shell interpretation. You also need to use --group on @@ -547,14 +533,6 @@ PERF_RECORD_SWITCH_CPU_WIDE. In some cases (e.g. Intel PT, CoreSight or Arm SPE) switch events will be enabled automatically, which can be suppressed by by the option --no-switch-events. ---clang-path=PATH:: -Path to clang binary to use for compiling BPF scriptlets. -(enabled when BPF support is on) - ---clang-opt=OPTIONS:: -Options passed to clang when compiling BPF scriptlets. -(enabled when BPF support is on) - --vmlinux=PATH:: Specify vmlinux path which has debuginfo. (enabled when BPF prologue is on) diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index e0592ed4c10f5..d66b52407e19c 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -589,18 +589,6 @@ ifndef NO_LIBELF LIBBPF_STATIC := 1 endif endif - - ifndef NO_DWARF - ifdef PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET - CFLAGS += -DHAVE_BPF_PROLOGUE - $(call detected,CONFIG_BPF_PROLOGUE) - else - msg := $(warning BPF prologue is not supported by architecture $(SRCARCH), missing regs_query_register_offset()); - endif - else - msg := $(warning DWARF support is off, BPF prologue is disabled); - endif - endif # NO_LIBBPF endif # NO_LIBELF diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index aec18db7ff238..34bb31f08bb52 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -37,8 +37,6 @@ #include "util/parse-branch-options.h" #include "util/parse-regs-options.h" #include "util/perf_api_probe.h" -#include "util/llvm-utils.h" -#include "util/bpf-loader.h" #include "util/trigger.h" #include "util/perf-hooks.h" #include "util/cpu-set-sched.h" @@ -2465,16 +2463,6 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) } } - err = bpf__apply_obj_config(); - if (err) { - char errbuf[BUFSIZ]; - - bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf)); - pr_err("ERROR: Apply config to BPF failed: %s\n", - errbuf); - goto out_free_threads; - } - /* * Normally perf_session__new would do this, but it doesn't have the * evlist. @@ -3486,10 +3474,6 @@ static struct option __record_options[] = { "collect kernel callchains"), OPT_BOOLEAN(0, "user-callchains", &record.opts.user_callchains, "collect user callchains"), - OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path", - "clang binary to use for compiling BPF scriptlets"), - OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options", - "options passed to clang when compiling BPF scriptlets"), OPT_STRING(0, "vmlinux", &symbol_conf.vmlinux_name, "file", "vmlinux pathname"), OPT_BOOLEAN(0, "buildid-all", &record.buildid_all, @@ -3967,27 +3951,6 @@ int cmd_record(int argc, const char **argv) setlocale(LC_ALL, ""); -#ifndef HAVE_LIBBPF_SUPPORT -# define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, "NO_LIBBPF=1", c) - set_nobuild('\0', "clang-path", true); - set_nobuild('\0', "clang-opt", true); -# undef set_nobuild -#endif - -#ifndef HAVE_BPF_PROLOGUE -# if !defined (HAVE_DWARF_SUPPORT) -# define REASON "NO_DWARF=1" -# elif !defined (HAVE_LIBBPF_SUPPORT) -# define REASON "NO_LIBBPF=1" -# else -# define REASON "this architecture doesn't support BPF prologue" -# endif -# define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, REASON, c) - set_nobuild('\0', "vmlinux", true); -# undef set_nobuild -# undef REASON -#endif - #ifndef HAVE_BPF_SKEL # define set_nobuild(s, l, m, c) set_option_nobuild(record_options, s, l, m, c) set_nobuild('\0', "off-cpu", "no BUILD_BPF_SKEL=1", true); @@ -4116,14 +4079,6 @@ int cmd_record(int argc, const char **argv) if (dry_run) goto out; - err = bpf__setup_stdout(rec->evlist); - if (err) { - bpf__strerror_setup_stdout(rec->evlist, err, errbuf, sizeof(errbuf)); - pr_err("ERROR: Setup BPF stdout failed: %s\n", - errbuf); - goto out; - } - err = -ENOMEM; if (rec->no_buildid_cache || rec->no_buildid) { diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 7ece2521efb69..59862467e781f 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -18,6 +18,7 @@ #include #ifdef HAVE_LIBBPF_SUPPORT #include +#include #endif #include "util/bpf_map.h" #include "util/rlimit.h" @@ -53,7 +54,6 @@ #include "trace/beauty/beauty.h" #include "trace-event.h" #include "util/parse-events.h" -#include "util/bpf-loader.h" #include "util/tracepoint.h" #include "callchain.h" #include "print_binary.h" @@ -3287,17 +3287,6 @@ static struct bpf_map *trace__find_bpf_map_by_name(struct trace *trace, const ch return bpf_object__find_map_by_name(trace->bpf_obj, name); } -static void trace__set_bpf_map_filtered_pids(struct trace *trace) -{ - trace->filter_pids.map = trace__find_bpf_map_by_name(trace, "pids_filtered"); -} - -static void trace__set_bpf_map_syscalls(struct trace *trace) -{ - trace->syscalls.prog_array.sys_enter = trace__find_bpf_map_by_name(trace, "syscalls_sys_enter"); - trace->syscalls.prog_array.sys_exit = trace__find_bpf_map_by_name(trace, "syscalls_sys_exit"); -} - static struct bpf_program *trace__find_bpf_program_by_title(struct trace *trace, const char *name) { struct bpf_program *pos, *prog = NULL; @@ -3553,25 +3542,6 @@ static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace) return err; } -static void trace__delete_augmented_syscalls(struct trace *trace) -{ - struct evsel *evsel, *tmp; - - evlist__remove(trace->evlist, trace->syscalls.events.augmented); - evsel__delete(trace->syscalls.events.augmented); - trace->syscalls.events.augmented = NULL; - - evlist__for_each_entry_safe(trace->evlist, tmp, evsel) { - if (evsel->bpf_obj == trace->bpf_obj) { - evlist__remove(trace->evlist, evsel); - evsel__delete(evsel); - } - - } - - bpf_object__close(trace->bpf_obj); - trace->bpf_obj = NULL; -} #else // HAVE_LIBBPF_SUPPORT static struct bpf_map *trace__find_bpf_map_by_name(struct trace *trace __maybe_unused, const char *name __maybe_unused) @@ -3579,45 +3549,12 @@ static struct bpf_map *trace__find_bpf_map_by_name(struct trace *trace __maybe_u return NULL; } -static void trace__set_bpf_map_filtered_pids(struct trace *trace __maybe_unused) -{ -} - -static void trace__set_bpf_map_syscalls(struct trace *trace __maybe_unused) -{ -} - -static struct bpf_program *trace__find_bpf_program_by_title(struct trace *trace __maybe_unused, - const char *name __maybe_unused) -{ - return NULL; -} - static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace __maybe_unused) { return 0; } - -static void trace__delete_augmented_syscalls(struct trace *trace __maybe_unused) -{ -} #endif // HAVE_LIBBPF_SUPPORT -static bool trace__only_augmented_syscalls_evsels(struct trace *trace) -{ - struct evsel *evsel; - - evlist__for_each_entry(trace->evlist, evsel) { - if (evsel == trace->syscalls.events.augmented || - evsel->bpf_obj == trace->bpf_obj) - continue; - - return false; - } - - return true; -} - static int trace__set_ev_qualifier_filter(struct trace *trace) { if (trace->syscalls.events.sys_enter) @@ -3981,16 +3918,6 @@ static int trace__run(struct trace *trace, int argc, const char **argv) if (err < 0) goto out_error_open; - err = bpf__apply_obj_config(); - if (err) { - char errbuf[BUFSIZ]; - - bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf)); - pr_err("ERROR: Apply config to BPF failed: %s\n", - errbuf); - goto out_error_open; - } - err = trace__set_filter_pids(trace); if (err < 0) goto out_error_mem; @@ -4922,77 +4849,6 @@ int cmd_trace(int argc, const char **argv) "cgroup monitoring only available in system-wide mode"); } - evsel = bpf__setup_output_event(trace.evlist, "__augmented_syscalls__"); - if (IS_ERR(evsel)) { - bpf__strerror_setup_output_event(trace.evlist, PTR_ERR(evsel), bf, sizeof(bf)); - pr_err("ERROR: Setup trace syscalls enter failed: %s\n", bf); - goto out; - } - - if (evsel) { - trace.syscalls.events.augmented = evsel; - - evsel = evlist__find_tracepoint_by_name(trace.evlist, "raw_syscalls:sys_enter"); - if (evsel == NULL) { - pr_err("ERROR: raw_syscalls:sys_enter not found in the augmented BPF object\n"); - goto out; - } - - if (evsel->bpf_obj == NULL) { - pr_err("ERROR: raw_syscalls:sys_enter not associated to a BPF object\n"); - goto out; - } - - trace.bpf_obj = evsel->bpf_obj; - - /* - * If we have _just_ the augmenter event but don't have a - * explicit --syscalls, then assume we want all strace-like - * syscalls: - */ - if (!trace.trace_syscalls && trace__only_augmented_syscalls_evsels(&trace)) - trace.trace_syscalls = true; - /* - * So, if we have a syscall augmenter, but trace_syscalls, aka - * strace-like syscall tracing is not set, then we need to trow - * away the augmenter, i.e. all the events that were created - * from that BPF object file. - * - * This is more to fix the current .perfconfig trace.add_events - * style of setting up the strace-like eBPF based syscall point - * payload augmenter. - * - * All this complexity will be avoided by adding an alternative - * to trace.add_events in the form of - * trace.bpf_augmented_syscalls, that will be only parsed if we - * need it. - * - * .perfconfig trace.add_events is still useful if we want, for - * instance, have msr_write.msr in some .perfconfig profile based - * 'perf trace --config determinism.profile' mode, where for some - * particular goal/workload type we want a set of events and - * output mode (with timings, etc) instead of having to add - * all via the command line. - * - * Also --config to specify an alternate .perfconfig file needs - * to be implemented. - */ - if (!trace.trace_syscalls) { - trace__delete_augmented_syscalls(&trace); - } else { - trace__set_bpf_map_filtered_pids(&trace); - trace__set_bpf_map_syscalls(&trace); - trace.syscalls.unaugmented_prog = trace__find_bpf_program_by_title(&trace, "!raw_syscalls:unaugmented"); - } - } - - err = bpf__setup_stdout(trace.evlist); - if (err) { - bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf)); - pr_err("ERROR: Setup BPF stdout failed: %s\n", bf); - goto out; - } - err = -1; if (map_dump_str) { diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 38cae4721583d..d3fc8090413c8 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -18,7 +18,6 @@ #include #include "util/parse-events.h" #include -#include "util/bpf-loader.h" #include "util/debug.h" #include "util/event.h" #include "util/util.h" // usage() @@ -324,7 +323,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) perf_config__exit(); exit_browser(status); perf_env__exit(&perf_env); - bpf__clear(); if (status) return status & 0xff; diff --git a/tools/perf/tests/.gitignore b/tools/perf/tests/.gitignore deleted file mode 100644 index d053b325f7285..0000000000000 --- a/tools/perf/tests/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -llvm-src-base.c -llvm-src-kbuild.c -llvm-src-prologue.c -llvm-src-relocation.c diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index 52df5923a8b9c..63d5e6d5f165b 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -37,8 +37,6 @@ perf-y += sample-parsing.o perf-y += parse-no-sample-id-all.o perf-y += kmod-path.o perf-y += thread-map.o -perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o llvm-src-prologue.o llvm-src-relocation.o -perf-y += bpf.o perf-y += topology.o perf-y += mem.o perf-y += cpumap.o @@ -69,34 +67,6 @@ perf-y += sigtrap.o perf-y += event_groups.o perf-y += symbols.o -$(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build - $(call rule_mkdir) - $(Q)echo '#include ' > $@ - $(Q)echo 'const char test_llvm__bpf_base_prog[] =' >> $@ - $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@ - $(Q)echo ';' >> $@ - -$(OUTPUT)tests/llvm-src-kbuild.c: tests/bpf-script-test-kbuild.c tests/Build - $(call rule_mkdir) - $(Q)echo '#include ' > $@ - $(Q)echo 'const char test_llvm__bpf_test_kbuild_prog[] =' >> $@ - $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@ - $(Q)echo ';' >> $@ - -$(OUTPUT)tests/llvm-src-prologue.c: tests/bpf-script-test-prologue.c tests/Build - $(call rule_mkdir) - $(Q)echo '#include ' > $@ - $(Q)echo 'const char test_llvm__bpf_test_prologue_prog[] =' >> $@ - $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@ - $(Q)echo ';' >> $@ - -$(OUTPUT)tests/llvm-src-relocation.c: tests/bpf-script-test-relocation.c tests/Build - $(call rule_mkdir) - $(Q)echo '#include ' > $@ - $(Q)echo 'const char test_llvm__bpf_test_relocation[] =' >> $@ - $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@ - $(Q)echo ';' >> $@ - ifeq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc)) perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o endif diff --git a/tools/perf/tests/bpf-script-example.c b/tools/perf/tests/bpf-script-example.c deleted file mode 100644 index b638cc99d5ae5..0000000000000 --- a/tools/perf/tests/bpf-script-example.c +++ /dev/null @@ -1,60 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * bpf-script-example.c - * Test basic LLVM building - */ -#ifndef LINUX_VERSION_CODE -# error Need LINUX_VERSION_CODE -# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig' -#endif -#define BPF_ANY 0 -#define BPF_MAP_TYPE_ARRAY 2 -#define BPF_FUNC_map_lookup_elem 1 -#define BPF_FUNC_map_update_elem 2 - -static void *(*bpf_map_lookup_elem)(void *map, void *key) = - (void *) BPF_FUNC_map_lookup_elem; -static void *(*bpf_map_update_elem)(void *map, void *key, void *value, int flags) = - (void *) BPF_FUNC_map_update_elem; - -/* - * Following macros are taken from tools/lib/bpf/bpf_helpers.h, - * and are used to create BTF defined maps. It is easier to take - * 2 simple macros, than being able to include above header in - * runtime. - * - * __uint - defines integer attribute of BTF map definition, - * Such attributes are represented using a pointer to an array, - * in which dimensionality of array encodes specified integer - * value. - * - * __type - defines pointer variable with typeof(val) type for - * attributes like key or value, which will be defined by the - * size of the type. - */ -#define __uint(name, val) int (*name)[val] -#define __type(name, val) typeof(val) *name - -#define SEC(NAME) __attribute__((section(NAME), used)) -struct { - __uint(type, BPF_MAP_TYPE_ARRAY); - __uint(max_entries, 1); - __type(key, int); - __type(value, int); -} flip_table SEC(".maps"); - -SEC("syscalls:sys_enter_epoll_pwait") -int bpf_func__SyS_epoll_pwait(void *ctx) -{ - int ind =0; - int *flag = bpf_map_lookup_elem(&flip_table, &ind); - int new_flag; - if (!flag) - return 0; - /* flip flag and store back */ - new_flag = !*flag; - bpf_map_update_elem(&flip_table, &ind, &new_flag, BPF_ANY); - return new_flag; -} -char _license[] SEC("license") = "GPL"; -int _version SEC("version") = LINUX_VERSION_CODE; diff --git a/tools/perf/tests/bpf-script-test-kbuild.c b/tools/perf/tests/bpf-script-test-kbuild.c deleted file mode 100644 index 219673aa278fb..0000000000000 --- a/tools/perf/tests/bpf-script-test-kbuild.c +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * bpf-script-test-kbuild.c - * Test include from kernel header - */ -#ifndef LINUX_VERSION_CODE -# error Need LINUX_VERSION_CODE -# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig' -#endif -#define SEC(NAME) __attribute__((section(NAME), used)) - -#include - -SEC("func=vfs_llseek") -int bpf_func__vfs_llseek(void *ctx) -{ - return 0; -} - -char _license[] SEC("license") = "GPL"; -int _version SEC("version") = LINUX_VERSION_CODE; diff --git a/tools/perf/tests/bpf-script-test-prologue.c b/tools/perf/tests/bpf-script-test-prologue.c deleted file mode 100644 index 91778b5c6125d..0000000000000 --- a/tools/perf/tests/bpf-script-test-prologue.c +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * bpf-script-test-prologue.c - * Test BPF prologue - */ -#ifndef LINUX_VERSION_CODE -# error Need LINUX_VERSION_CODE -# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig' -#endif -#define SEC(NAME) __attribute__((section(NAME), used)) - -#include - -/* - * If CONFIG_PROFILE_ALL_BRANCHES is selected, - * 'if' is redefined after include kernel header. - * Recover 'if' for BPF object code. - */ -#ifdef if -# undef if -#endif - -typedef unsigned int __bitwise fmode_t; - -#define FMODE_READ 0x1 -#define FMODE_WRITE 0x2 - -static void (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = - (void *) 6; - -SEC("func=null_lseek file->f_mode offset orig") -int bpf_func__null_lseek(void *ctx, int err, unsigned long _f_mode, - unsigned long offset, unsigned long orig) -{ - fmode_t f_mode = (fmode_t)_f_mode; - - if (err) - return 0; - if (f_mode & FMODE_WRITE) - return 0; - if (offset & 1) - return 0; - if (orig == SEEK_CUR) - return 0; - return 1; -} - -char _license[] SEC("license") = "GPL"; -int _version SEC("version") = LINUX_VERSION_CODE; diff --git a/tools/perf/tests/bpf-script-test-relocation.c b/tools/perf/tests/bpf-script-test-relocation.c deleted file mode 100644 index 74006e4b2d248..0000000000000 --- a/tools/perf/tests/bpf-script-test-relocation.c +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * bpf-script-test-relocation.c - * Test BPF loader checking relocation - */ -#ifndef LINUX_VERSION_CODE -# error Need LINUX_VERSION_CODE -# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig' -#endif -#define BPF_ANY 0 -#define BPF_MAP_TYPE_ARRAY 2 -#define BPF_FUNC_map_lookup_elem 1 -#define BPF_FUNC_map_update_elem 2 - -static void *(*bpf_map_lookup_elem)(void *map, void *key) = - (void *) BPF_FUNC_map_lookup_elem; -static void *(*bpf_map_update_elem)(void *map, void *key, void *value, int flags) = - (void *) BPF_FUNC_map_update_elem; - -struct bpf_map_def { - unsigned int type; - unsigned int key_size; - unsigned int value_size; - unsigned int max_entries; -}; - -#define SEC(NAME) __attribute__((section(NAME), used)) -struct bpf_map_def SEC("maps") my_table = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(int), - .value_size = sizeof(int), - .max_entries = 1, -}; - -int this_is_a_global_val; - -SEC("func=sys_write") -int bpf_func__sys_write(void *ctx) -{ - int key = 0; - int value = 0; - - /* - * Incorrect relocation. Should not allow this program be - * loaded into kernel. - */ - bpf_map_update_elem(&this_is_a_global_val, &key, &value, 0); - return 0; -} -char _license[] SEC("license") = "GPL"; -int _version SEC("version") = LINUX_VERSION_CODE; diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c deleted file mode 100644 index 9ccecd873ecdd..0000000000000 --- a/tools/perf/tests/bpf.c +++ /dev/null @@ -1,390 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "tests.h" -#include "llvm.h" -#include "debug.h" -#include "parse-events.h" -#include "util/mmap.h" -#define NR_ITERS 111 -#define PERF_TEST_BPF_PATH "/sys/fs/bpf/perf_test" - -#if defined(HAVE_LIBBPF_SUPPORT) && defined(HAVE_LIBTRACEEVENT) -#include -#include - -static int epoll_pwait_loop(void) -{ - struct epoll_event events; - int i; - - /* Should fail NR_ITERS times */ - for (i = 0; i < NR_ITERS; i++) - epoll_pwait(-(i + 1), &events, 0, 0, NULL); - return 0; -} - -#ifdef HAVE_BPF_PROLOGUE - -static int llseek_loop(void) -{ - int fds[2], i; - - fds[0] = open("/dev/null", O_RDONLY); - fds[1] = open("/dev/null", O_RDWR); - - if (fds[0] < 0 || fds[1] < 0) - return -1; - - for (i = 0; i < NR_ITERS; i++) { - lseek(fds[i % 2], i, (i / 2) % 2 ? SEEK_CUR : SEEK_SET); - lseek(fds[(i + 1) % 2], i, (i / 2) % 2 ? SEEK_CUR : SEEK_SET); - } - close(fds[0]); - close(fds[1]); - return 0; -} - -#endif - -static struct { - enum test_llvm__testcase prog_id; - const char *name; - const char *msg_compile_fail; - const char *msg_load_fail; - int (*target_func)(void); - int expect_result; - bool pin; -} bpf_testcase_table[] = { - { - .prog_id = LLVM_TESTCASE_BASE, - .name = "[basic_bpf_test]", - .msg_compile_fail = "fix 'perf test LLVM' first", - .msg_load_fail = "load bpf object failed", - .target_func = &epoll_pwait_loop, - .expect_result = (NR_ITERS + 1) / 2, - }, - { - .prog_id = LLVM_TESTCASE_BASE, - .name = "[bpf_pinning]", - .msg_compile_fail = "fix kbuild first", - .msg_load_fail = "check your vmlinux setting?", - .target_func = &epoll_pwait_loop, - .expect_result = (NR_ITERS + 1) / 2, - .pin = true, - }, -#ifdef HAVE_BPF_PROLOGUE - { - .prog_id = LLVM_TESTCASE_BPF_PROLOGUE, - .name = "[bpf_prologue_test]", - .msg_compile_fail = "fix kbuild first", - .msg_load_fail = "check your vmlinux setting?", - .target_func = &llseek_loop, - .expect_result = (NR_ITERS + 1) / 4, - }, -#endif -}; - -static int do_test(struct bpf_object *obj, int (*func)(void), - int expect) -{ - struct record_opts opts = { - .target = { - .uid = UINT_MAX, - .uses_mmap = true, - }, - .freq = 0, - .mmap_pages = 256, - .default_interval = 1, - }; - - char pid[16]; - char sbuf[STRERR_BUFSIZE]; - struct evlist *evlist; - int i, ret = TEST_FAIL, err = 0, count = 0; - - struct parse_events_state parse_state; - struct parse_events_error parse_error; - - parse_events_error__init(&parse_error); - bzero(&parse_state, sizeof(parse_state)); - parse_state.error = &parse_error; - INIT_LIST_HEAD(&parse_state.list); - - err = parse_events_load_bpf_obj(&parse_state, &parse_state.list, obj, NULL, NULL); - parse_events_error__exit(&parse_error); - if (err == -ENODATA) { - pr_debug("Failed to add events selected by BPF, debuginfo package not installed\n"); - return TEST_SKIP; - } - if (err || list_empty(&parse_state.list)) { - pr_debug("Failed to add events selected by BPF\n"); - return TEST_FAIL; - } - - snprintf(pid, sizeof(pid), "%d", getpid()); - pid[sizeof(pid) - 1] = '\0'; - opts.target.tid = opts.target.pid = pid; - - /* Instead of evlist__new_default, don't add default events */ - evlist = evlist__new(); - if (!evlist) { - pr_debug("Not enough memory to create evlist\n"); - return TEST_FAIL; - } - - err = evlist__create_maps(evlist, &opts.target); - if (err < 0) { - pr_debug("Not enough memory to create thread/cpu maps\n"); - goto out_delete_evlist; - } - - evlist__splice_list_tail(evlist, &parse_state.list); - - evlist__config(evlist, &opts, NULL); - - err = evlist__open(evlist); - if (err < 0) { - pr_debug("perf_evlist__open: %s\n", - str_error_r(errno, sbuf, sizeof(sbuf))); - goto out_delete_evlist; - } - - err = evlist__mmap(evlist, opts.mmap_pages); - if (err < 0) { - pr_debug("evlist__mmap: %s\n", - str_error_r(errno, sbuf, sizeof(sbuf))); - goto out_delete_evlist; - } - - evlist__enable(evlist); - (*func)(); - evlist__disable(evlist); - - for (i = 0; i < evlist->core.nr_mmaps; i++) { - union perf_event *event; - struct mmap *md; - - md = &evlist->mmap[i]; - if (perf_mmap__read_init(&md->core) < 0) - continue; - - while ((event = perf_mmap__read_event(&md->core)) != NULL) { - const u32 type = event->header.type; - - if (type == PERF_RECORD_SAMPLE) - count ++; - } - perf_mmap__read_done(&md->core); - } - - if (count != expect * evlist->core.nr_entries) { - pr_debug("BPF filter result incorrect, expected %d, got %d samples\n", expect * evlist->core.nr_entries, count); - goto out_delete_evlist; - } - - ret = TEST_OK; - -out_delete_evlist: - evlist__delete(evlist); - return ret; -} - -static struct bpf_object * -prepare_bpf(void *obj_buf, size_t obj_buf_sz, const char *name) -{ - struct bpf_object *obj; - - obj = bpf__prepare_load_buffer(obj_buf, obj_buf_sz, name); - if (IS_ERR(obj)) { - pr_debug("Compile BPF program failed.\n"); - return NULL; - } - return obj; -} - -static int __test__bpf(int idx) -{ - int ret; - void *obj_buf; - size_t obj_buf_sz; - struct bpf_object *obj; - - ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz, - bpf_testcase_table[idx].prog_id, - false, NULL); - if (ret != TEST_OK || !obj_buf || !obj_buf_sz) { - pr_debug("Unable to get BPF object, %s\n", - bpf_testcase_table[idx].msg_compile_fail); - if ((idx == 0) || (ret == TEST_SKIP)) - return TEST_SKIP; - else - return TEST_FAIL; - } - - obj = prepare_bpf(obj_buf, obj_buf_sz, - bpf_testcase_table[idx].name); - if ((!!bpf_testcase_table[idx].target_func) != (!!obj)) { - if (!obj) - pr_debug("Fail to load BPF object: %s\n", - bpf_testcase_table[idx].msg_load_fail); - else - pr_debug("Success unexpectedly: %s\n", - bpf_testcase_table[idx].msg_load_fail); - ret = TEST_FAIL; - goto out; - } - - if (obj) { - ret = do_test(obj, - bpf_testcase_table[idx].target_func, - bpf_testcase_table[idx].expect_result); - if (ret != TEST_OK) - goto out; - if (bpf_testcase_table[idx].pin) { - int err; - - if (!bpf_fs__mount()) { - pr_debug("BPF filesystem not mounted\n"); - ret = TEST_FAIL; - goto out; - } - err = mkdir(PERF_TEST_BPF_PATH, 0777); - if (err && errno != EEXIST) { - pr_debug("Failed to make perf_test dir: %s\n", - strerror(errno)); - ret = TEST_FAIL; - goto out; - } - if (bpf_object__pin(obj, PERF_TEST_BPF_PATH)) - ret = TEST_FAIL; - if (rm_rf(PERF_TEST_BPF_PATH)) - ret = TEST_FAIL; - } - } - -out: - free(obj_buf); - bpf__clear(); - return ret; -} - -static int check_env(void) -{ - LIBBPF_OPTS(bpf_prog_load_opts, opts); - int err; - char license[] = "GPL"; - - struct bpf_insn insns[] = { - BPF_MOV64_IMM(BPF_REG_0, 1), - BPF_EXIT_INSN(), - }; - - err = fetch_kernel_version(&opts.kern_version, NULL, 0); - if (err) { - pr_debug("Unable to get kernel version\n"); - return err; - } - err = bpf_prog_load(BPF_PROG_TYPE_KPROBE, NULL, license, insns, - ARRAY_SIZE(insns), &opts); - if (err < 0) { - pr_err("Missing basic BPF support, skip this test: %s\n", - strerror(errno)); - return err; - } - close(err); - - return 0; -} - -static int test__bpf(int i) -{ - int err; - - if (i < 0 || i >= (int)ARRAY_SIZE(bpf_testcase_table)) - return TEST_FAIL; - - if (geteuid() != 0) { - pr_debug("Only root can run BPF test\n"); - return TEST_SKIP; - } - - if (check_env()) - return TEST_SKIP; - - err = __test__bpf(i); - return err; -} -#endif - -static int test__basic_bpf_test(struct test_suite *test __maybe_unused, - int subtest __maybe_unused) -{ -#if defined(HAVE_LIBBPF_SUPPORT) && defined(HAVE_LIBTRACEEVENT) - return test__bpf(0); -#else - pr_debug("Skip BPF test because BPF or libtraceevent support is not compiled\n"); - return TEST_SKIP; -#endif -} - -static int test__bpf_pinning(struct test_suite *test __maybe_unused, - int subtest __maybe_unused) -{ -#if defined(HAVE_LIBBPF_SUPPORT) && defined(HAVE_LIBTRACEEVENT) - return test__bpf(1); -#else - pr_debug("Skip BPF test because BPF or libtraceevent support is not compiled\n"); - return TEST_SKIP; -#endif -} - -static int test__bpf_prologue_test(struct test_suite *test __maybe_unused, - int subtest __maybe_unused) -{ -#if defined(HAVE_LIBBPF_SUPPORT) && defined(HAVE_BPF_PROLOGUE) && defined(HAVE_LIBTRACEEVENT) - return test__bpf(2); -#else - pr_debug("Skip BPF test because BPF or libtraceevent support is not compiled\n"); - return TEST_SKIP; -#endif -} - - -static struct test_case bpf_tests[] = { -#if defined(HAVE_LIBBPF_SUPPORT) && defined(HAVE_LIBTRACEEVENT) - TEST_CASE("Basic BPF filtering", basic_bpf_test), - TEST_CASE_REASON("BPF pinning", bpf_pinning, - "clang isn't installed or environment missing BPF support"), -#ifdef HAVE_BPF_PROLOGUE - TEST_CASE_REASON("BPF prologue generation", bpf_prologue_test, - "clang/debuginfo isn't installed or environment missing BPF support"), -#else - TEST_CASE_REASON("BPF prologue generation", bpf_prologue_test, "not compiled in"), -#endif -#else - TEST_CASE_REASON("Basic BPF filtering", basic_bpf_test, "not compiled in or missing libtraceevent support"), - TEST_CASE_REASON("BPF pinning", bpf_pinning, "not compiled in or missing libtraceevent support"), - TEST_CASE_REASON("BPF prologue generation", bpf_prologue_test, "not compiled in or missing libtraceevent support"), -#endif - { .name = NULL, } -}; - -struct test_suite suite__bpf = { - .desc = "BPF filter", - .test_cases = bpf_tests, -}; diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 0f3691fd31c25..0ad18cf6dd226 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -92,9 +92,7 @@ static struct test_suite *generic_tests[] = { &suite__fdarray__add, &suite__kmod_path__parse, &suite__thread_map, - &suite__llvm, &suite__session_topology, - &suite__bpf, &suite__thread_map_synthesize, &suite__thread_map_remove, &suite__cpu_map, diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c deleted file mode 100644 index 0bc25a56cfef4..0000000000000 --- a/tools/perf/tests/llvm.c +++ /dev/null @@ -1,219 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include "tests.h" -#include "debug.h" - -#ifdef HAVE_LIBBPF_SUPPORT -#include -#include -#include "llvm.h" -static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz) -{ - struct bpf_object *obj; - - obj = bpf_object__open_mem(obj_buf, obj_buf_sz, NULL); - if (libbpf_get_error(obj)) - return TEST_FAIL; - bpf_object__close(obj); - return TEST_OK; -} - -static struct { - const char *source; - const char *desc; - bool should_load_fail; -} bpf_source_table[__LLVM_TESTCASE_MAX] = { - [LLVM_TESTCASE_BASE] = { - .source = test_llvm__bpf_base_prog, - .desc = "Basic BPF llvm compile", - }, - [LLVM_TESTCASE_KBUILD] = { - .source = test_llvm__bpf_test_kbuild_prog, - .desc = "kbuild searching", - }, - [LLVM_TESTCASE_BPF_PROLOGUE] = { - .source = test_llvm__bpf_test_prologue_prog, - .desc = "Compile source for BPF prologue generation", - }, - [LLVM_TESTCASE_BPF_RELOCATION] = { - .source = test_llvm__bpf_test_relocation, - .desc = "Compile source for BPF relocation", - .should_load_fail = true, - }, -}; - -int -test_llvm__fetch_bpf_obj(void **p_obj_buf, - size_t *p_obj_buf_sz, - enum test_llvm__testcase idx, - bool force, - bool *should_load_fail) -{ - const char *source; - const char *desc; - const char *tmpl_old, *clang_opt_old; - char *tmpl_new = NULL, *clang_opt_new = NULL; - int err, old_verbose, ret = TEST_FAIL; - - if (idx >= __LLVM_TESTCASE_MAX) - return TEST_FAIL; - - source = bpf_source_table[idx].source; - desc = bpf_source_table[idx].desc; - if (should_load_fail) - *should_load_fail = bpf_source_table[idx].should_load_fail; - - /* - * Skip this test if user's .perfconfig doesn't set [llvm] section - * and clang is not found in $PATH - */ - if (!force && (!llvm_param.user_set_param && - llvm__search_clang())) { - pr_debug("No clang, skip this test\n"); - return TEST_SKIP; - } - - /* - * llvm is verbosity when error. Suppress all error output if - * not 'perf test -v'. - */ - old_verbose = verbose; - if (verbose == 0) - verbose = -1; - - *p_obj_buf = NULL; - *p_obj_buf_sz = 0; - - if (!llvm_param.clang_bpf_cmd_template) - goto out; - - if (!llvm_param.clang_opt) - llvm_param.clang_opt = strdup(""); - - err = asprintf(&tmpl_new, "echo '%s' | %s%s", source, - llvm_param.clang_bpf_cmd_template, - old_verbose ? "" : " 2>/dev/null"); - if (err < 0) - goto out; - err = asprintf(&clang_opt_new, "-xc %s", llvm_param.clang_opt); - if (err < 0) - goto out; - - tmpl_old = llvm_param.clang_bpf_cmd_template; - llvm_param.clang_bpf_cmd_template = tmpl_new; - clang_opt_old = llvm_param.clang_opt; - llvm_param.clang_opt = clang_opt_new; - - err = llvm__compile_bpf("-", p_obj_buf, p_obj_buf_sz); - - llvm_param.clang_bpf_cmd_template = tmpl_old; - llvm_param.clang_opt = clang_opt_old; - - verbose = old_verbose; - if (err) - goto out; - - ret = TEST_OK; -out: - free(tmpl_new); - free(clang_opt_new); - if (ret != TEST_OK) - pr_debug("Failed to compile test case: '%s'\n", desc); - return ret; -} - -static int test__llvm(int subtest) -{ - int ret; - void *obj_buf = NULL; - size_t obj_buf_sz = 0; - bool should_load_fail = false; - - if ((subtest < 0) || (subtest >= __LLVM_TESTCASE_MAX)) - return TEST_FAIL; - - ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz, - subtest, false, &should_load_fail); - - if (ret == TEST_OK && !should_load_fail) { - ret = test__bpf_parsing(obj_buf, obj_buf_sz); - if (ret != TEST_OK) { - pr_debug("Failed to parse test case '%s'\n", - bpf_source_table[subtest].desc); - } - } - free(obj_buf); - - return ret; -} -#endif //HAVE_LIBBPF_SUPPORT - -static int test__llvm__bpf_base_prog(struct test_suite *test __maybe_unused, - int subtest __maybe_unused) -{ -#ifdef HAVE_LIBBPF_SUPPORT - return test__llvm(LLVM_TESTCASE_BASE); -#else - pr_debug("Skip LLVM test because BPF support is not compiled\n"); - return TEST_SKIP; -#endif -} - -static int test__llvm__bpf_test_kbuild_prog(struct test_suite *test __maybe_unused, - int subtest __maybe_unused) -{ -#ifdef HAVE_LIBBPF_SUPPORT - return test__llvm(LLVM_TESTCASE_KBUILD); -#else - pr_debug("Skip LLVM test because BPF support is not compiled\n"); - return TEST_SKIP; -#endif -} - -static int test__llvm__bpf_test_prologue_prog(struct test_suite *test __maybe_unused, - int subtest __maybe_unused) -{ -#ifdef HAVE_LIBBPF_SUPPORT - return test__llvm(LLVM_TESTCASE_BPF_PROLOGUE); -#else - pr_debug("Skip LLVM test because BPF support is not compiled\n"); - return TEST_SKIP; -#endif -} - -static int test__llvm__bpf_test_relocation(struct test_suite *test __maybe_unused, - int subtest __maybe_unused) -{ -#ifdef HAVE_LIBBPF_SUPPORT - return test__llvm(LLVM_TESTCASE_BPF_RELOCATION); -#else - pr_debug("Skip LLVM test because BPF support is not compiled\n"); - return TEST_SKIP; -#endif -} - - -static struct test_case llvm_tests[] = { -#ifdef HAVE_LIBBPF_SUPPORT - TEST_CASE("Basic BPF llvm compile", llvm__bpf_base_prog), - TEST_CASE("kbuild searching", llvm__bpf_test_kbuild_prog), - TEST_CASE("Compile source for BPF prologue generation", - llvm__bpf_test_prologue_prog), - TEST_CASE("Compile source for BPF relocation", llvm__bpf_test_relocation), -#else - TEST_CASE_REASON("Basic BPF llvm compile", llvm__bpf_base_prog, "not compiled in"), - TEST_CASE_REASON("kbuild searching", llvm__bpf_test_kbuild_prog, "not compiled in"), - TEST_CASE_REASON("Compile source for BPF prologue generation", - llvm__bpf_test_prologue_prog, "not compiled in"), - TEST_CASE_REASON("Compile source for BPF relocation", - llvm__bpf_test_relocation, "not compiled in"), -#endif - { .name = NULL, } -}; - -struct test_suite suite__llvm = { - .desc = "LLVM search and compile", - .test_cases = llvm_tests, -}; diff --git a/tools/perf/tests/llvm.h b/tools/perf/tests/llvm.h deleted file mode 100644 index f68b0d9b8ae28..0000000000000 --- a/tools/perf/tests/llvm.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef PERF_TEST_LLVM_H -#define PERF_TEST_LLVM_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include /* for size_t */ -#include /* for bool */ - -extern const char test_llvm__bpf_base_prog[]; -extern const char test_llvm__bpf_test_kbuild_prog[]; -extern const char test_llvm__bpf_test_prologue_prog[]; -extern const char test_llvm__bpf_test_relocation[]; - -enum test_llvm__testcase { - LLVM_TESTCASE_BASE, - LLVM_TESTCASE_KBUILD, - LLVM_TESTCASE_BPF_PROLOGUE, - LLVM_TESTCASE_BPF_RELOCATION, - __LLVM_TESTCASE_MAX, -}; - -int test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz, - enum test_llvm__testcase index, bool force, - bool *should_load_fail); -#ifdef __cplusplus -} -#endif -#endif diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index f424c0b7f43f9..f33cfc3c19a48 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -113,7 +113,6 @@ DECLARE_SUITE(fdarray__filter); DECLARE_SUITE(fdarray__add); DECLARE_SUITE(kmod_path__parse); DECLARE_SUITE(thread_map); -DECLARE_SUITE(llvm); DECLARE_SUITE(bpf); DECLARE_SUITE(session_topology); DECLARE_SUITE(thread_map_synthesize); @@ -129,7 +128,6 @@ DECLARE_SUITE(sdt_event); DECLARE_SUITE(is_printable_array); DECLARE_SUITE(bitmap_print); DECLARE_SUITE(perf_hooks); -DECLARE_SUITE(clang); DECLARE_SUITE(unit_number__scnprint); DECLARE_SUITE(mem2node); DECLARE_SUITE(maps__merge_in); diff --git a/tools/perf/util/Build b/tools/perf/util/Build index ff3b55c7ed43c..c6650d3fb066d 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -23,7 +23,6 @@ perf-y += evswitch.o perf-y += find_bit.o perf-y += get_current_dir_name.o perf-y += levenshtein.o -perf-y += llvm-utils.o perf-y += mmap.o perf-y += memswap.o perf-y += parse-events.o @@ -150,7 +149,6 @@ perf-y += list_sort.o perf-y += mutex.o perf-y += sharded_mutex.o -perf-$(CONFIG_LIBBPF) += bpf-loader.o perf-$(CONFIG_LIBBPF) += bpf_map.o perf-$(CONFIG_PERF_BPF_SKEL) += bpf_counter.o perf-$(CONFIG_PERF_BPF_SKEL) += bpf_counter_cgroup.o @@ -168,7 +166,6 @@ ifeq ($(CONFIG_LIBTRACEEVENT),y) perf-$(CONFIG_PERF_BPF_SKEL) += bpf_kwork.o endif -perf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o perf-$(CONFIG_LIBELF) += symbol-elf.o perf-$(CONFIG_LIBELF) += probe-file.o perf-$(CONFIG_LIBELF) += probe-event.o @@ -235,7 +232,6 @@ perf-$(CONFIG_LIBBPF) += bpf-utils.o perf-$(CONFIG_LIBPFM4) += pfm.o CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" -CFLAGS_llvm-utils.o += -DLIBBPF_INCLUDE_DIR="BUILD_STR($(libbpf_include_dir_SQ))" # avoid compiler warnings in 32-bit mode CFLAGS_genelf_debug.o += -Wno-packed @@ -327,7 +323,7 @@ ifeq ($(BISON_LT_381),1) bison_flags += -DYYNOMEM=YYABORT endif -CFLAGS_parse-events-flex.o += $(flex_flags) +CFLAGS_parse-events-flex.o += $(flex_flags) -Wno-unused-label CFLAGS_pmu-flex.o += $(flex_flags) CFLAGS_expr-flex.o += $(flex_flags) CFLAGS_bpf-filter-flex.o += $(flex_flags) diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c deleted file mode 100644 index b54e42f17926b..0000000000000 --- a/tools/perf/util/bpf-loader.c +++ /dev/null @@ -1,1999 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * bpf-loader.c - * - * Copyright (C) 2015 Wang Nan - * Copyright (C) 2015 Huawei Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "debug.h" -#include "evlist.h" -#include "bpf-loader.h" -#include "bpf-prologue.h" -#include "probe-event.h" -#include "probe-finder.h" // for MAX_PROBES -#include "parse-events.h" -#include "strfilter.h" -#include "util.h" -#include "llvm-utils.h" -#include "util/hashmap.h" -#include "asm/bug.h" - -#include - -static int libbpf_perf_print(enum libbpf_print_level level __attribute__((unused)), - const char *fmt, va_list args) -{ - return veprintf(1, verbose, pr_fmt(fmt), args); -} - -struct bpf_prog_priv { - bool is_tp; - char *sys_name; - char *evt_name; - struct perf_probe_event pev; - bool need_prologue; - struct bpf_insn *insns_buf; - int nr_types; - int *type_mapping; - int *prologue_fds; -}; - -struct bpf_perf_object { - struct list_head list; - struct bpf_object *obj; -}; - -struct bpf_preproc_result { - struct bpf_insn *new_insn_ptr; - int new_insn_cnt; -}; - -static LIST_HEAD(bpf_objects_list); -static struct hashmap *bpf_program_hash; -static struct hashmap *bpf_map_hash; - -static struct bpf_perf_object * -bpf_perf_object__next(struct bpf_perf_object *prev) -{ - if (!prev) { - if (list_empty(&bpf_objects_list)) - return NULL; - - return list_first_entry(&bpf_objects_list, struct bpf_perf_object, list); - } - if (list_is_last(&prev->list, &bpf_objects_list)) - return NULL; - - return list_next_entry(prev, list); -} - -#define bpf_perf_object__for_each(perf_obj, tmp) \ - for ((perf_obj) = bpf_perf_object__next(NULL), \ - (tmp) = bpf_perf_object__next(perf_obj); \ - (perf_obj) != NULL; \ - (perf_obj) = (tmp), (tmp) = bpf_perf_object__next(tmp)) - -static bool libbpf_initialized; -static int libbpf_sec_handler; - -static int bpf_perf_object__add(struct bpf_object *obj) -{ - struct bpf_perf_object *perf_obj = zalloc(sizeof(*perf_obj)); - - if (perf_obj) { - INIT_LIST_HEAD(&perf_obj->list); - perf_obj->obj = obj; - list_add_tail(&perf_obj->list, &bpf_objects_list); - } - return perf_obj ? 0 : -ENOMEM; -} - -static void *program_priv(const struct bpf_program *prog) -{ - void *priv; - - if (IS_ERR_OR_NULL(bpf_program_hash)) - return NULL; - if (!hashmap__find(bpf_program_hash, prog, &priv)) - return NULL; - return priv; -} - -static struct bpf_insn prologue_init_insn[] = { - BPF_MOV64_IMM(BPF_REG_2, 0), - BPF_MOV64_IMM(BPF_REG_3, 0), - BPF_MOV64_IMM(BPF_REG_4, 0), - BPF_MOV64_IMM(BPF_REG_5, 0), -}; - -static int libbpf_prog_prepare_load_fn(struct bpf_program *prog, - struct bpf_prog_load_opts *opts __maybe_unused, - long cookie __maybe_unused) -{ - size_t init_size_cnt = ARRAY_SIZE(prologue_init_insn); - size_t orig_insn_cnt, insn_cnt, init_size, orig_size; - struct bpf_prog_priv *priv = program_priv(prog); - const struct bpf_insn *orig_insn; - struct bpf_insn *insn; - - if (IS_ERR_OR_NULL(priv)) { - pr_debug("bpf: failed to get private field\n"); - return -BPF_LOADER_ERRNO__INTERNAL; - } - - if (!priv->need_prologue) - return 0; - - /* prepend initialization code to program instructions */ - orig_insn = bpf_program__insns(prog); - orig_insn_cnt = bpf_program__insn_cnt(prog); - init_size = init_size_cnt * sizeof(*insn); - orig_size = orig_insn_cnt * sizeof(*insn); - - insn_cnt = orig_insn_cnt + init_size_cnt; - insn = malloc(insn_cnt * sizeof(*insn)); - if (!insn) - return -ENOMEM; - - memcpy(insn, prologue_init_insn, init_size); - memcpy((char *) insn + init_size, orig_insn, orig_size); - bpf_program__set_insns(prog, insn, insn_cnt); - return 0; -} - -static int libbpf_init(void) -{ - LIBBPF_OPTS(libbpf_prog_handler_opts, handler_opts, - .prog_prepare_load_fn = libbpf_prog_prepare_load_fn, - ); - - if (libbpf_initialized) - return 0; - - libbpf_set_print(libbpf_perf_print); - libbpf_sec_handler = libbpf_register_prog_handler(NULL, BPF_PROG_TYPE_KPROBE, - 0, &handler_opts); - if (libbpf_sec_handler < 0) { - pr_debug("bpf: failed to register libbpf section handler: %d\n", - libbpf_sec_handler); - return -BPF_LOADER_ERRNO__INTERNAL; - } - libbpf_initialized = true; - return 0; -} - -struct bpf_object * -bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz, const char *name) -{ - LIBBPF_OPTS(bpf_object_open_opts, opts, .object_name = name); - struct bpf_object *obj; - int err; - - err = libbpf_init(); - if (err) - return ERR_PTR(err); - - obj = bpf_object__open_mem(obj_buf, obj_buf_sz, &opts); - if (IS_ERR_OR_NULL(obj)) { - pr_debug("bpf: failed to load buffer\n"); - return ERR_PTR(-EINVAL); - } - - if (bpf_perf_object__add(obj)) { - bpf_object__close(obj); - return ERR_PTR(-ENOMEM); - } - - return obj; -} - -static void bpf_perf_object__close(struct bpf_perf_object *perf_obj) -{ - list_del(&perf_obj->list); - bpf_object__close(perf_obj->obj); - free(perf_obj); -} - -struct bpf_object *bpf__prepare_load(const char *filename, bool source) -{ - LIBBPF_OPTS(bpf_object_open_opts, opts, .object_name = filename); - struct bpf_object *obj; - int err; - - err = libbpf_init(); - if (err) - return ERR_PTR(err); - - if (source) { - void *obj_buf; - size_t obj_buf_sz; - - err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz); - if (err) - return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE); - - obj = bpf_object__open_mem(obj_buf, obj_buf_sz, &opts); - - if (!IS_ERR_OR_NULL(obj) && llvm_param.dump_obj) - llvm__dump_obj(filename, obj_buf, obj_buf_sz); - - free(obj_buf); - } else { - obj = bpf_object__open(filename); - } - - if (IS_ERR_OR_NULL(obj)) { - pr_debug("bpf: failed to load %s\n", filename); - return obj; - } - - if (bpf_perf_object__add(obj)) { - bpf_object__close(obj); - return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE); - } - - return obj; -} - -static void close_prologue_programs(struct bpf_prog_priv *priv) -{ - struct perf_probe_event *pev; - int i, fd; - - if (!priv->need_prologue) - return; - pev = &priv->pev; - for (i = 0; i < pev->ntevs; i++) { - fd = priv->prologue_fds[i]; - if (fd != -1) - close(fd); - } -} - -static void -clear_prog_priv(const struct bpf_program *prog __maybe_unused, - void *_priv) -{ - struct bpf_prog_priv *priv = _priv; - - close_prologue_programs(priv); - cleanup_perf_probe_events(&priv->pev, 1); - zfree(&priv->insns_buf); - zfree(&priv->prologue_fds); - zfree(&priv->type_mapping); - zfree(&priv->sys_name); - zfree(&priv->evt_name); - free(priv); -} - -static void bpf_program_hash_free(void) -{ - struct hashmap_entry *cur; - size_t bkt; - - if (IS_ERR_OR_NULL(bpf_program_hash)) - return; - - hashmap__for_each_entry(bpf_program_hash, cur, bkt) - clear_prog_priv(cur->pkey, cur->pvalue); - - hashmap__free(bpf_program_hash); - bpf_program_hash = NULL; -} - -static void bpf_map_hash_free(void); - -void bpf__clear(void) -{ - struct bpf_perf_object *perf_obj, *tmp; - - bpf_perf_object__for_each(perf_obj, tmp) { - bpf__unprobe(perf_obj->obj); - bpf_perf_object__close(perf_obj); - } - - bpf_program_hash_free(); - bpf_map_hash_free(); -} - -static size_t ptr_hash(const long __key, void *ctx __maybe_unused) -{ - return __key; -} - -static bool ptr_equal(long key1, long key2, void *ctx __maybe_unused) -{ - return key1 == key2; -} - -static int program_set_priv(struct bpf_program *prog, void *priv) -{ - void *old_priv; - - /* - * Should not happen, we warn about it in the - * caller function - config_bpf_program - */ - if (IS_ERR(bpf_program_hash)) - return PTR_ERR(bpf_program_hash); - - if (!bpf_program_hash) { - bpf_program_hash = hashmap__new(ptr_hash, ptr_equal, NULL); - if (IS_ERR(bpf_program_hash)) - return PTR_ERR(bpf_program_hash); - } - - old_priv = program_priv(prog); - if (old_priv) { - clear_prog_priv(prog, old_priv); - return hashmap__set(bpf_program_hash, prog, priv, NULL, NULL); - } - return hashmap__add(bpf_program_hash, prog, priv); -} - -static int -prog_config__exec(const char *value, struct perf_probe_event *pev) -{ - pev->uprobes = true; - pev->target = strdup(value); - if (!pev->target) - return -ENOMEM; - return 0; -} - -static int -prog_config__module(const char *value, struct perf_probe_event *pev) -{ - pev->uprobes = false; - pev->target = strdup(value); - if (!pev->target) - return -ENOMEM; - return 0; -} - -static int -prog_config__bool(const char *value, bool *pbool, bool invert) -{ - int err; - bool bool_value; - - if (!pbool) - return -EINVAL; - - err = strtobool(value, &bool_value); - if (err) - return err; - - *pbool = invert ? !bool_value : bool_value; - return 0; -} - -static int -prog_config__inlines(const char *value, - struct perf_probe_event *pev __maybe_unused) -{ - return prog_config__bool(value, &probe_conf.no_inlines, true); -} - -static int -prog_config__force(const char *value, - struct perf_probe_event *pev __maybe_unused) -{ - return prog_config__bool(value, &probe_conf.force_add, false); -} - -static struct { - const char *key; - const char *usage; - const char *desc; - int (*func)(const char *, struct perf_probe_event *); -} bpf_prog_config_terms[] = { - { - .key = "exec", - .usage = "exec=", - .desc = "Set uprobe target", - .func = prog_config__exec, - }, - { - .key = "module", - .usage = "module= ", - .desc = "Set kprobe module", - .func = prog_config__module, - }, - { - .key = "inlines", - .usage = "inlines=[yes|no] ", - .desc = "Probe at inline symbol", - .func = prog_config__inlines, - }, - { - .key = "force", - .usage = "force=[yes|no] ", - .desc = "Forcibly add events with existing name", - .func = prog_config__force, - }, -}; - -static int -do_prog_config(const char *key, const char *value, - struct perf_probe_event *pev) -{ - unsigned int i; - - pr_debug("config bpf program: %s=%s\n", key, value); - for (i = 0; i < ARRAY_SIZE(bpf_prog_config_terms); i++) - if (strcmp(key, bpf_prog_config_terms[i].key) == 0) - return bpf_prog_config_terms[i].func(value, pev); - - pr_debug("BPF: ERROR: invalid program config option: %s=%s\n", - key, value); - - pr_debug("\nHint: Valid options are:\n"); - for (i = 0; i < ARRAY_SIZE(bpf_prog_config_terms); i++) - pr_debug("\t%s:\t%s\n", bpf_prog_config_terms[i].usage, - bpf_prog_config_terms[i].desc); - pr_debug("\n"); - - return -BPF_LOADER_ERRNO__PROGCONF_TERM; -} - -static const char * -parse_prog_config_kvpair(const char *config_str, struct perf_probe_event *pev) -{ - char *text = strdup(config_str); - char *sep, *line; - const char *main_str = NULL; - int err = 0; - - if (!text) { - pr_debug("Not enough memory: dup config_str failed\n"); - return ERR_PTR(-ENOMEM); - } - - line = text; - while ((sep = strchr(line, ';'))) { - char *equ; - - *sep = '\0'; - equ = strchr(line, '='); - if (!equ) { - pr_warning("WARNING: invalid config in BPF object: %s\n", - line); - pr_warning("\tShould be 'key=value'.\n"); - goto nextline; - } - *equ = '\0'; - - err = do_prog_config(line, equ + 1, pev); - if (err) - break; -nextline: - line = sep + 1; - } - - if (!err) - main_str = config_str + (line - text); - free(text); - - return err ? ERR_PTR(err) : main_str; -} - -static int -parse_prog_config(const char *config_str, const char **p_main_str, - bool *is_tp, struct perf_probe_event *pev) -{ - int err; - const char *main_str = parse_prog_config_kvpair(config_str, pev); - - if (IS_ERR(main_str)) - return PTR_ERR(main_str); - - *p_main_str = main_str; - if (!strchr(main_str, '=')) { - /* Is a tracepoint event? */ - const char *s = strchr(main_str, ':'); - - if (!s) { - pr_debug("bpf: '%s' is not a valid tracepoint\n", - config_str); - return -BPF_LOADER_ERRNO__CONFIG; - } - - *is_tp = true; - return 0; - } - - *is_tp = false; - err = parse_perf_probe_command(main_str, pev); - if (err < 0) { - pr_debug("bpf: '%s' is not a valid config string\n", - config_str); - /* parse failed, don't need clear pev. */ - return -BPF_LOADER_ERRNO__CONFIG; - } - return 0; -} - -static int -config_bpf_program(struct bpf_program *prog) -{ - struct perf_probe_event *pev = NULL; - struct bpf_prog_priv *priv = NULL; - const char *config_str, *main_str; - bool is_tp = false; - int err; - - /* Initialize per-program probing setting */ - probe_conf.no_inlines = false; - probe_conf.force_add = false; - - priv = calloc(sizeof(*priv), 1); - if (!priv) { - pr_debug("bpf: failed to alloc priv\n"); - return -ENOMEM; - } - pev = &priv->pev; - - config_str = bpf_program__section_name(prog); - pr_debug("bpf: config program '%s'\n", config_str); - err = parse_prog_config(config_str, &main_str, &is_tp, pev); - if (err) - goto errout; - - if (is_tp) { - char *s = strchr(main_str, ':'); - - priv->is_tp = true; - priv->sys_name = strndup(main_str, s - main_str); - priv->evt_name = strdup(s + 1); - goto set_priv; - } - - if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) { - pr_debug("bpf: '%s': group for event is set and not '%s'.\n", - config_str, PERF_BPF_PROBE_GROUP); - err = -BPF_LOADER_ERRNO__GROUP; - goto errout; - } else if (!pev->group) - pev->group = strdup(PERF_BPF_PROBE_GROUP); - - if (!pev->group) { - pr_debug("bpf: strdup failed\n"); - err = -ENOMEM; - goto errout; - } - - if (!pev->event) { - pr_debug("bpf: '%s': event name is missing. Section name should be 'key=value'\n", - config_str); - err = -BPF_LOADER_ERRNO__EVENTNAME; - goto errout; - } - pr_debug("bpf: config '%s' is ok\n", config_str); - -set_priv: - err = program_set_priv(prog, priv); - if (err) { - pr_debug("Failed to set priv for program '%s'\n", config_str); - goto errout; - } - - return 0; - -errout: - if (pev) - clear_perf_probe_event(pev); - free(priv); - return err; -} - -static int bpf__prepare_probe(void) -{ - static int err = 0; - static bool initialized = false; - - /* - * Make err static, so if init failed the first, bpf__prepare_probe() - * fails each time without calling init_probe_symbol_maps multiple - * times. - */ - if (initialized) - return err; - - initialized = true; - err = init_probe_symbol_maps(false); - if (err < 0) - pr_debug("Failed to init_probe_symbol_maps\n"); - probe_conf.max_probes = MAX_PROBES; - return err; -} - -static int -preproc_gen_prologue(struct bpf_program *prog, int n, - const struct bpf_insn *orig_insns, int orig_insns_cnt, - struct bpf_preproc_result *res) -{ - struct bpf_prog_priv *priv = program_priv(prog); - struct probe_trace_event *tev; - struct perf_probe_event *pev; - struct bpf_insn *buf; - size_t prologue_cnt = 0; - int i, err; - - if (IS_ERR_OR_NULL(priv) || priv->is_tp) - goto errout; - - pev = &priv->pev; - - if (n < 0 || n >= priv->nr_types) - goto errout; - - /* Find a tev belongs to that type */ - for (i = 0; i < pev->ntevs; i++) { - if (priv->type_mapping[i] == n) - break; - } - - if (i >= pev->ntevs) { - pr_debug("Internal error: prologue type %d not found\n", n); - return -BPF_LOADER_ERRNO__PROLOGUE; - } - - tev = &pev->tevs[i]; - - buf = priv->insns_buf; - err = bpf__gen_prologue(tev->args, tev->nargs, - buf, &prologue_cnt, - BPF_MAXINSNS - orig_insns_cnt); - if (err) { - const char *title; - - title = bpf_program__section_name(prog); - pr_debug("Failed to generate prologue for program %s\n", - title); - return err; - } - - memcpy(&buf[prologue_cnt], orig_insns, - sizeof(struct bpf_insn) * orig_insns_cnt); - - res->new_insn_ptr = buf; - res->new_insn_cnt = prologue_cnt + orig_insns_cnt; - return 0; - -errout: - pr_debug("Internal error in preproc_gen_prologue\n"); - return -BPF_LOADER_ERRNO__PROLOGUE; -} - -/* - * compare_tev_args is reflexive, transitive and antisymmetric. - * I can proof it but this margin is too narrow to contain. - */ -static int compare_tev_args(const void *ptev1, const void *ptev2) -{ - int i, ret; - const struct probe_trace_event *tev1 = - *(const struct probe_trace_event **)ptev1; - const struct probe_trace_event *tev2 = - *(const struct probe_trace_event **)ptev2; - - ret = tev2->nargs - tev1->nargs; - if (ret) - return ret; - - for (i = 0; i < tev1->nargs; i++) { - struct probe_trace_arg *arg1, *arg2; - struct probe_trace_arg_ref *ref1, *ref2; - - arg1 = &tev1->args[i]; - arg2 = &tev2->args[i]; - - ret = strcmp(arg1->value, arg2->value); - if (ret) - return ret; - - ref1 = arg1->ref; - ref2 = arg2->ref; - - while (ref1 && ref2) { - ret = ref2->offset - ref1->offset; - if (ret) - return ret; - - ref1 = ref1->next; - ref2 = ref2->next; - } - - if (ref1 || ref2) - return ref2 ? 1 : -1; - } - - return 0; -} - -/* - * Assign a type number to each tevs in a pev. - * mapping is an array with same slots as tevs in that pev. - * nr_types will be set to number of types. - */ -static int map_prologue(struct perf_probe_event *pev, int *mapping, - int *nr_types) -{ - int i, type = 0; - struct probe_trace_event **ptevs; - - size_t array_sz = sizeof(*ptevs) * pev->ntevs; - - ptevs = malloc(array_sz); - if (!ptevs) { - pr_debug("Not enough memory: alloc ptevs failed\n"); - return -ENOMEM; - } - - pr_debug("In map_prologue, ntevs=%d\n", pev->ntevs); - for (i = 0; i < pev->ntevs; i++) - ptevs[i] = &pev->tevs[i]; - - qsort(ptevs, pev->ntevs, sizeof(*ptevs), - compare_tev_args); - - for (i = 0; i < pev->ntevs; i++) { - int n; - - n = ptevs[i] - pev->tevs; - if (i == 0) { - mapping[n] = type; - pr_debug("mapping[%d]=%d\n", n, type); - continue; - } - - if (compare_tev_args(ptevs + i, ptevs + i - 1) == 0) - mapping[n] = type; - else - mapping[n] = ++type; - - pr_debug("mapping[%d]=%d\n", n, mapping[n]); - } - free(ptevs); - *nr_types = type + 1; - - return 0; -} - -static int hook_load_preprocessor(struct bpf_program *prog) -{ - struct bpf_prog_priv *priv = program_priv(prog); - struct perf_probe_event *pev; - bool need_prologue = false; - int i; - - if (IS_ERR_OR_NULL(priv)) { - pr_debug("Internal error when hook preprocessor\n"); - return -BPF_LOADER_ERRNO__INTERNAL; - } - - if (priv->is_tp) { - priv->need_prologue = false; - return 0; - } - - pev = &priv->pev; - for (i = 0; i < pev->ntevs; i++) { - struct probe_trace_event *tev = &pev->tevs[i]; - - if (tev->nargs > 0) { - need_prologue = true; - break; - } - } - - /* - * Since all tevs don't have argument, we don't need generate - * prologue. - */ - if (!need_prologue) { - priv->need_prologue = false; - return 0; - } - - priv->need_prologue = true; - priv->insns_buf = malloc(sizeof(struct bpf_insn) * BPF_MAXINSNS); - if (!priv->insns_buf) { - pr_debug("Not enough memory: alloc insns_buf failed\n"); - return -ENOMEM; - } - - priv->prologue_fds = malloc(sizeof(int) * pev->ntevs); - if (!priv->prologue_fds) { - pr_debug("Not enough memory: alloc prologue fds failed\n"); - return -ENOMEM; - } - memset(priv->prologue_fds, -1, sizeof(int) * pev->ntevs); - - priv->type_mapping = malloc(sizeof(int) * pev->ntevs); - if (!priv->type_mapping) { - pr_debug("Not enough memory: alloc type_mapping failed\n"); - return -ENOMEM; - } - memset(priv->type_mapping, -1, - sizeof(int) * pev->ntevs); - - return map_prologue(pev, priv->type_mapping, &priv->nr_types); -} - -int bpf__probe(struct bpf_object *obj) -{ - int err = 0; - struct bpf_program *prog; - struct bpf_prog_priv *priv; - struct perf_probe_event *pev; - - err = bpf__prepare_probe(); - if (err) { - pr_debug("bpf__prepare_probe failed\n"); - return err; - } - - bpf_object__for_each_program(prog, obj) { - err = config_bpf_program(prog); - if (err) - goto out; - - priv = program_priv(prog); - if (IS_ERR_OR_NULL(priv)) { - if (!priv) - err = -BPF_LOADER_ERRNO__INTERNAL; - else - err = PTR_ERR(priv); - goto out; - } - - if (priv->is_tp) { - bpf_program__set_type(prog, BPF_PROG_TYPE_TRACEPOINT); - continue; - } - - bpf_program__set_type(prog, BPF_PROG_TYPE_KPROBE); - pev = &priv->pev; - - err = convert_perf_probe_events(pev, 1); - if (err < 0) { - pr_debug("bpf_probe: failed to convert perf probe events\n"); - goto out; - } - - err = apply_perf_probe_events(pev, 1); - if (err < 0) { - pr_debug("bpf_probe: failed to apply perf probe events\n"); - goto out; - } - - /* - * After probing, let's consider prologue, which - * adds program fetcher to BPF programs. - * - * hook_load_preprocessor() hooks pre-processor - * to bpf_program, let it generate prologue - * dynamically during loading. - */ - err = hook_load_preprocessor(prog); - if (err) - goto out; - } -out: - return err < 0 ? err : 0; -} - -#define EVENTS_WRITE_BUFSIZE 4096 -int bpf__unprobe(struct bpf_object *obj) -{ - int err, ret = 0; - struct bpf_program *prog; - - bpf_object__for_each_program(prog, obj) { - struct bpf_prog_priv *priv = program_priv(prog); - int i; - - if (IS_ERR_OR_NULL(priv) || priv->is_tp) - continue; - - for (i = 0; i < priv->pev.ntevs; i++) { - struct probe_trace_event *tev = &priv->pev.tevs[i]; - char name_buf[EVENTS_WRITE_BUFSIZE]; - struct strfilter *delfilter; - - snprintf(name_buf, EVENTS_WRITE_BUFSIZE, - "%s:%s", tev->group, tev->event); - name_buf[EVENTS_WRITE_BUFSIZE - 1] = '\0'; - - delfilter = strfilter__new(name_buf, NULL); - if (!delfilter) { - pr_debug("Failed to create filter for unprobing\n"); - ret = -ENOMEM; - continue; - } - - err = del_perf_probe_events(delfilter); - strfilter__delete(delfilter); - if (err) { - pr_debug("Failed to delete %s\n", name_buf); - ret = err; - continue; - } - } - } - return ret; -} - -static int bpf_object__load_prologue(struct bpf_object *obj) -{ - int init_cnt = ARRAY_SIZE(prologue_init_insn); - const struct bpf_insn *orig_insns; - struct bpf_preproc_result res; - struct perf_probe_event *pev; - struct bpf_program *prog; - int orig_insns_cnt; - - bpf_object__for_each_program(prog, obj) { - struct bpf_prog_priv *priv = program_priv(prog); - int err, i, fd; - - if (IS_ERR_OR_NULL(priv)) { - pr_debug("bpf: failed to get private field\n"); - return -BPF_LOADER_ERRNO__INTERNAL; - } - - if (!priv->need_prologue) - continue; - - /* - * For each program that needs prologue we do following: - * - * - take its current instructions and use them - * to generate the new code with prologue - * - load new instructions with bpf_prog_load - * and keep the fd in prologue_fds - * - new fd will be used in bpf__foreach_event - * to connect this program with perf evsel - */ - orig_insns = bpf_program__insns(prog); - orig_insns_cnt = bpf_program__insn_cnt(prog); - - pev = &priv->pev; - for (i = 0; i < pev->ntevs; i++) { - /* - * Skipping artificall prologue_init_insn instructions - * (init_cnt), so the prologue can be generated instead - * of them. - */ - err = preproc_gen_prologue(prog, i, - orig_insns + init_cnt, - orig_insns_cnt - init_cnt, - &res); - if (err) - return err; - - fd = bpf_prog_load(bpf_program__get_type(prog), - bpf_program__name(prog), "GPL", - res.new_insn_ptr, - res.new_insn_cnt, NULL); - if (fd < 0) { - char bf[128]; - - libbpf_strerror(-errno, bf, sizeof(bf)); - pr_debug("bpf: load objects with prologue failed: err=%d: (%s)\n", - -errno, bf); - return -errno; - } - priv->prologue_fds[i] = fd; - } - /* - * We no longer need the original program, - * we can unload it. - */ - bpf_program__unload(prog); - } - return 0; -} - -int bpf__load(struct bpf_object *obj) -{ - int err; - - err = bpf_object__load(obj); - if (err) { - char bf[128]; - libbpf_strerror(err, bf, sizeof(bf)); - pr_debug("bpf: load objects failed: err=%d: (%s)\n", err, bf); - return err; - } - return bpf_object__load_prologue(obj); -} - -int bpf__foreach_event(struct bpf_object *obj, - bpf_prog_iter_callback_t func, - void *arg) -{ - struct bpf_program *prog; - int err; - - bpf_object__for_each_program(prog, obj) { - struct bpf_prog_priv *priv = program_priv(prog); - struct probe_trace_event *tev; - struct perf_probe_event *pev; - int i, fd; - - if (IS_ERR_OR_NULL(priv)) { - pr_debug("bpf: failed to get private field\n"); - return -BPF_LOADER_ERRNO__INTERNAL; - } - - if (priv->is_tp) { - fd = bpf_program__fd(prog); - err = (*func)(priv->sys_name, priv->evt_name, fd, obj, arg); - if (err) { - pr_debug("bpf: tracepoint call back failed, stop iterate\n"); - return err; - } - continue; - } - - pev = &priv->pev; - for (i = 0; i < pev->ntevs; i++) { - tev = &pev->tevs[i]; - - if (priv->need_prologue) - fd = priv->prologue_fds[i]; - else - fd = bpf_program__fd(prog); - - if (fd < 0) { - pr_debug("bpf: failed to get file descriptor\n"); - return fd; - } - - err = (*func)(tev->group, tev->event, fd, obj, arg); - if (err) { - pr_debug("bpf: call back failed, stop iterate\n"); - return err; - } - } - } - return 0; -} - -enum bpf_map_op_type { - BPF_MAP_OP_SET_VALUE, - BPF_MAP_OP_SET_EVSEL, -}; - -enum bpf_map_key_type { - BPF_MAP_KEY_ALL, -}; - -struct bpf_map_op { - struct list_head list; - enum bpf_map_op_type op_type; - enum bpf_map_key_type key_type; - union { - u64 value; - struct evsel *evsel; - } v; -}; - -struct bpf_map_priv { - struct list_head ops_list; -}; - -static void -bpf_map_op__delete(struct bpf_map_op *op) -{ - if (!list_empty(&op->list)) - list_del_init(&op->list); - free(op); -} - -static void -bpf_map_priv__purge(struct bpf_map_priv *priv) -{ - struct bpf_map_op *pos, *n; - - list_for_each_entry_safe(pos, n, &priv->ops_list, list) { - list_del_init(&pos->list); - bpf_map_op__delete(pos); - } -} - -static void -bpf_map_priv__clear(const struct bpf_map *map __maybe_unused, - void *_priv) -{ - struct bpf_map_priv *priv = _priv; - - bpf_map_priv__purge(priv); - free(priv); -} - -static void *map_priv(const struct bpf_map *map) -{ - void *priv; - - if (IS_ERR_OR_NULL(bpf_map_hash)) - return NULL; - if (!hashmap__find(bpf_map_hash, map, &priv)) - return NULL; - return priv; -} - -static void bpf_map_hash_free(void) -{ - struct hashmap_entry *cur; - size_t bkt; - - if (IS_ERR_OR_NULL(bpf_map_hash)) - return; - - hashmap__for_each_entry(bpf_map_hash, cur, bkt) - bpf_map_priv__clear(cur->pkey, cur->pvalue); - - hashmap__free(bpf_map_hash); - bpf_map_hash = NULL; -} - -static int map_set_priv(struct bpf_map *map, void *priv) -{ - void *old_priv; - - if (WARN_ON_ONCE(IS_ERR(bpf_map_hash))) - return PTR_ERR(bpf_program_hash); - - if (!bpf_map_hash) { - bpf_map_hash = hashmap__new(ptr_hash, ptr_equal, NULL); - if (IS_ERR(bpf_map_hash)) - return PTR_ERR(bpf_map_hash); - } - - old_priv = map_priv(map); - if (old_priv) { - bpf_map_priv__clear(map, old_priv); - return hashmap__set(bpf_map_hash, map, priv, NULL, NULL); - } - return hashmap__add(bpf_map_hash, map, priv); -} - -static int -bpf_map_op_setkey(struct bpf_map_op *op, struct parse_events_term *term) -{ - op->key_type = BPF_MAP_KEY_ALL; - if (!term) - return 0; - - return 0; -} - -static struct bpf_map_op * -bpf_map_op__new(struct parse_events_term *term) -{ - struct bpf_map_op *op; - int err; - - op = zalloc(sizeof(*op)); - if (!op) { - pr_debug("Failed to alloc bpf_map_op\n"); - return ERR_PTR(-ENOMEM); - } - INIT_LIST_HEAD(&op->list); - - err = bpf_map_op_setkey(op, term); - if (err) { - free(op); - return ERR_PTR(err); - } - return op; -} - -static struct bpf_map_op * -bpf_map_op__clone(struct bpf_map_op *op) -{ - struct bpf_map_op *newop; - - newop = memdup(op, sizeof(*op)); - if (!newop) { - pr_debug("Failed to alloc bpf_map_op\n"); - return NULL; - } - - INIT_LIST_HEAD(&newop->list); - return newop; -} - -static struct bpf_map_priv * -bpf_map_priv__clone(struct bpf_map_priv *priv) -{ - struct bpf_map_priv *newpriv; - struct bpf_map_op *pos, *newop; - - newpriv = zalloc(sizeof(*newpriv)); - if (!newpriv) { - pr_debug("Not enough memory to alloc map private\n"); - return NULL; - } - INIT_LIST_HEAD(&newpriv->ops_list); - - list_for_each_entry(pos, &priv->ops_list, list) { - newop = bpf_map_op__clone(pos); - if (!newop) { - bpf_map_priv__purge(newpriv); - return NULL; - } - list_add_tail(&newop->list, &newpriv->ops_list); - } - - return newpriv; -} - -static int -bpf_map__add_op(struct bpf_map *map, struct bpf_map_op *op) -{ - const char *map_name = bpf_map__name(map); - struct bpf_map_priv *priv = map_priv(map); - - if (IS_ERR(priv)) { - pr_debug("Failed to get private from map %s\n", map_name); - return PTR_ERR(priv); - } - - if (!priv) { - priv = zalloc(sizeof(*priv)); - if (!priv) { - pr_debug("Not enough memory to alloc map private\n"); - return -ENOMEM; - } - INIT_LIST_HEAD(&priv->ops_list); - - if (map_set_priv(map, priv)) { - free(priv); - return -BPF_LOADER_ERRNO__INTERNAL; - } - } - - list_add_tail(&op->list, &priv->ops_list); - return 0; -} - -static struct bpf_map_op * -bpf_map__add_newop(struct bpf_map *map, struct parse_events_term *term) -{ - struct bpf_map_op *op; - int err; - - op = bpf_map_op__new(term); - if (IS_ERR(op)) - return op; - - err = bpf_map__add_op(map, op); - if (err) { - bpf_map_op__delete(op); - return ERR_PTR(err); - } - return op; -} - -static int -__bpf_map__config_value(struct bpf_map *map, - struct parse_events_term *term) -{ - struct bpf_map_op *op; - const char *map_name = bpf_map__name(map); - - if (!map) { - pr_debug("Map '%s' is invalid\n", map_name); - return -BPF_LOADER_ERRNO__INTERNAL; - } - - if (bpf_map__type(map) != BPF_MAP_TYPE_ARRAY) { - pr_debug("Map %s type is not BPF_MAP_TYPE_ARRAY\n", - map_name); - return -BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE; - } - if (bpf_map__key_size(map) < sizeof(unsigned int)) { - pr_debug("Map %s has incorrect key size\n", map_name); - return -BPF_LOADER_ERRNO__OBJCONF_MAP_KEYSIZE; - } - switch (bpf_map__value_size(map)) { - case 1: - case 2: - case 4: - case 8: - break; - default: - pr_debug("Map %s has incorrect value size\n", map_name); - return -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUESIZE; - } - - op = bpf_map__add_newop(map, term); - if (IS_ERR(op)) - return PTR_ERR(op); - op->op_type = BPF_MAP_OP_SET_VALUE; - op->v.value = term->val.num; - return 0; -} - -static int -bpf_map__config_value(struct bpf_map *map, - struct parse_events_term *term, - struct evlist *evlist __maybe_unused) -{ - if (!term->err_val) { - pr_debug("Config value not set\n"); - return -BPF_LOADER_ERRNO__OBJCONF_CONF; - } - - if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM) { - pr_debug("ERROR: wrong value type for 'value'\n"); - return -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE; - } - - return __bpf_map__config_value(map, term); -} - -static int -__bpf_map__config_event(struct bpf_map *map, - struct parse_events_term *term, - struct evlist *evlist) -{ - struct bpf_map_op *op; - const char *map_name = bpf_map__name(map); - struct evsel *evsel = evlist__find_evsel_by_str(evlist, term->val.str); - - if (!evsel) { - pr_debug("Event (for '%s') '%s' doesn't exist\n", - map_name, term->val.str); - return -BPF_LOADER_ERRNO__OBJCONF_MAP_NOEVT; - } - - if (!map) { - pr_debug("Map '%s' is invalid\n", map_name); - return PTR_ERR(map); - } - - /* - * No need to check key_size and value_size: - * kernel has already checked them. - */ - if (bpf_map__type(map) != BPF_MAP_TYPE_PERF_EVENT_ARRAY) { - pr_debug("Map %s type is not BPF_MAP_TYPE_PERF_EVENT_ARRAY\n", - map_name); - return -BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE; - } - - op = bpf_map__add_newop(map, term); - if (IS_ERR(op)) - return PTR_ERR(op); - op->op_type = BPF_MAP_OP_SET_EVSEL; - op->v.evsel = evsel; - return 0; -} - -static int -bpf_map__config_event(struct bpf_map *map, - struct parse_events_term *term, - struct evlist *evlist) -{ - if (!term->err_val) { - pr_debug("Config value not set\n"); - return -BPF_LOADER_ERRNO__OBJCONF_CONF; - } - - if (term->type_val != PARSE_EVENTS__TERM_TYPE_STR) { - pr_debug("ERROR: wrong value type for 'event'\n"); - return -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE; - } - - return __bpf_map__config_event(map, term, evlist); -} - -struct bpf_obj_config__map_func { - const char *config_opt; - int (*config_func)(struct bpf_map *, struct parse_events_term *, - struct evlist *); -}; - -struct bpf_obj_config__map_func bpf_obj_config__map_funcs[] = { - {"value", bpf_map__config_value}, - {"event", bpf_map__config_event}, -}; - -static int -bpf__obj_config_map(struct bpf_object *obj, - struct parse_events_term *term, - struct evlist *evlist, - int *key_scan_pos) -{ - /* key is "map:." */ - char *map_name = strdup(term->config + sizeof("map:") - 1); - struct bpf_map *map; - int err = -BPF_LOADER_ERRNO__OBJCONF_OPT; - char *map_opt; - size_t i; - - if (!map_name) - return -ENOMEM; - - map_opt = strchr(map_name, '.'); - if (!map_opt) { - pr_debug("ERROR: Invalid map config: %s\n", map_name); - goto out; - } - - *map_opt++ = '\0'; - if (*map_opt == '\0') { - pr_debug("ERROR: Invalid map option: %s\n", term->config); - goto out; - } - - map = bpf_object__find_map_by_name(obj, map_name); - if (!map) { - pr_debug("ERROR: Map %s doesn't exist\n", map_name); - err = -BPF_LOADER_ERRNO__OBJCONF_MAP_NOTEXIST; - goto out; - } - - for (i = 0; i < ARRAY_SIZE(bpf_obj_config__map_funcs); i++) { - struct bpf_obj_config__map_func *func = - &bpf_obj_config__map_funcs[i]; - - if (strcmp(map_opt, func->config_opt) == 0) { - err = func->config_func(map, term, evlist); - goto out; - } - } - - pr_debug("ERROR: Invalid map config option '%s'\n", map_opt); - err = -BPF_LOADER_ERRNO__OBJCONF_MAP_OPT; -out: - if (!err) - *key_scan_pos += strlen(map_opt); - - free(map_name); - return err; -} - -int bpf__config_obj(struct bpf_object *obj, - struct parse_events_term *term, - struct evlist *evlist, - int *error_pos) -{ - int key_scan_pos = 0; - int err; - - if (!obj || !term || !term->config) - return -EINVAL; - - if (strstarts(term->config, "map:")) { - key_scan_pos = sizeof("map:") - 1; - err = bpf__obj_config_map(obj, term, evlist, &key_scan_pos); - goto out; - } - err = -BPF_LOADER_ERRNO__OBJCONF_OPT; -out: - if (error_pos) - *error_pos = key_scan_pos; - return err; - -} - -typedef int (*map_config_func_t)(const char *name, int map_fd, - const struct bpf_map *map, - struct bpf_map_op *op, - void *pkey, void *arg); -static int -foreach_key_array_all(map_config_func_t func, - void *arg, const char *name, - int map_fd, const struct bpf_map *map, - struct bpf_map_op *op) -{ - unsigned int i; - int err; - - for (i = 0; i < bpf_map__max_entries(map); i++) { - err = func(name, map_fd, map, op, &i, arg); - if (err) { - pr_debug("ERROR: failed to insert value to %s[%u]\n", - name, i); - return err; - } - } - return 0; -} - - -static int -bpf_map_config_foreach_key(struct bpf_map *map, - map_config_func_t func, - void *arg) -{ - int err, map_fd, type; - struct bpf_map_op *op; - const char *name = bpf_map__name(map); - struct bpf_map_priv *priv = map_priv(map); - - if (IS_ERR(priv)) { - pr_debug("ERROR: failed to get private from map %s\n", name); - return -BPF_LOADER_ERRNO__INTERNAL; - } - if (!priv || list_empty(&priv->ops_list)) { - pr_debug("INFO: nothing to config for map %s\n", name); - return 0; - } - - if (!map) { - pr_debug("Map '%s' is invalid\n", name); - return -BPF_LOADER_ERRNO__INTERNAL; - } - map_fd = bpf_map__fd(map); - if (map_fd < 0) { - pr_debug("ERROR: failed to get fd from map %s\n", name); - return map_fd; - } - - type = bpf_map__type(map); - list_for_each_entry(op, &priv->ops_list, list) { - switch (type) { - case BPF_MAP_TYPE_ARRAY: - case BPF_MAP_TYPE_PERF_EVENT_ARRAY: - switch (op->key_type) { - case BPF_MAP_KEY_ALL: - err = foreach_key_array_all(func, arg, name, - map_fd, map, op); - break; - default: - pr_debug("ERROR: keytype for map '%s' invalid\n", - name); - return -BPF_LOADER_ERRNO__INTERNAL; - } - if (err) - return err; - break; - default: - pr_debug("ERROR: type of '%s' incorrect\n", name); - return -BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE; - } - } - - return 0; -} - -static int -apply_config_value_for_key(int map_fd, void *pkey, - size_t val_size, u64 val) -{ - int err = 0; - - switch (val_size) { - case 1: { - u8 _val = (u8)(val); - err = bpf_map_update_elem(map_fd, pkey, &_val, BPF_ANY); - break; - } - case 2: { - u16 _val = (u16)(val); - err = bpf_map_update_elem(map_fd, pkey, &_val, BPF_ANY); - break; - } - case 4: { - u32 _val = (u32)(val); - err = bpf_map_update_elem(map_fd, pkey, &_val, BPF_ANY); - break; - } - case 8: { - err = bpf_map_update_elem(map_fd, pkey, &val, BPF_ANY); - break; - } - default: - pr_debug("ERROR: invalid value size\n"); - return -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUESIZE; - } - if (err && errno) - err = -errno; - return err; -} - -static int -apply_config_evsel_for_key(const char *name, int map_fd, void *pkey, - struct evsel *evsel) -{ - struct xyarray *xy = evsel->core.fd; - struct perf_event_attr *attr; - unsigned int key, events; - bool check_pass = false; - int *evt_fd; - int err; - - if (!xy) { - pr_debug("ERROR: evsel not ready for map %s\n", name); - return -BPF_LOADER_ERRNO__INTERNAL; - } - - if (xy->row_size / xy->entry_size != 1) { - pr_debug("ERROR: Dimension of target event is incorrect for map %s\n", - name); - return -BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM; - } - - attr = &evsel->core.attr; - if (attr->inherit) { - pr_debug("ERROR: Can't put inherit event into map %s\n", name); - return -BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH; - } - - if (evsel__is_bpf_output(evsel)) - check_pass = true; - if (attr->type == PERF_TYPE_RAW) - check_pass = true; - if (attr->type == PERF_TYPE_HARDWARE) - check_pass = true; - if (!check_pass) { - pr_debug("ERROR: Event type is wrong for map %s\n", name); - return -BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE; - } - - events = xy->entries / (xy->row_size / xy->entry_size); - key = *((unsigned int *)pkey); - if (key >= events) { - pr_debug("ERROR: there is no event %d for map %s\n", - key, name); - return -BPF_LOADER_ERRNO__OBJCONF_MAP_MAPSIZE; - } - evt_fd = xyarray__entry(xy, key, 0); - err = bpf_map_update_elem(map_fd, pkey, evt_fd, BPF_ANY); - if (err && errno) - err = -errno; - return err; -} - -static int -apply_obj_config_map_for_key(const char *name, int map_fd, - const struct bpf_map *map, - struct bpf_map_op *op, - void *pkey, void *arg __maybe_unused) -{ - int err; - - switch (op->op_type) { - case BPF_MAP_OP_SET_VALUE: - err = apply_config_value_for_key(map_fd, pkey, - bpf_map__value_size(map), - op->v.value); - break; - case BPF_MAP_OP_SET_EVSEL: - err = apply_config_evsel_for_key(name, map_fd, pkey, - op->v.evsel); - break; - default: - pr_debug("ERROR: unknown value type for '%s'\n", name); - err = -BPF_LOADER_ERRNO__INTERNAL; - } - return err; -} - -static int -apply_obj_config_map(struct bpf_map *map) -{ - return bpf_map_config_foreach_key(map, - apply_obj_config_map_for_key, - NULL); -} - -static int -apply_obj_config_object(struct bpf_object *obj) -{ - struct bpf_map *map; - int err; - - bpf_object__for_each_map(map, obj) { - err = apply_obj_config_map(map); - if (err) - return err; - } - return 0; -} - -int bpf__apply_obj_config(void) -{ - struct bpf_perf_object *perf_obj, *tmp; - int err; - - bpf_perf_object__for_each(perf_obj, tmp) { - err = apply_obj_config_object(perf_obj->obj); - if (err) - return err; - } - - return 0; -} - -#define bpf__perf_for_each_map(map, pobj, tmp) \ - bpf_perf_object__for_each(pobj, tmp) \ - bpf_object__for_each_map(map, pobj->obj) - -#define bpf__perf_for_each_map_named(map, pobj, pobjtmp, name) \ - bpf__perf_for_each_map(map, pobj, pobjtmp) \ - if (bpf_map__name(map) && (strcmp(name, bpf_map__name(map)) == 0)) - -struct evsel *bpf__setup_output_event(struct evlist *evlist, const char *name) -{ - struct bpf_map_priv *tmpl_priv = NULL; - struct bpf_perf_object *perf_obj, *tmp; - struct evsel *evsel = NULL; - struct bpf_map *map; - int err; - bool need_init = false; - - bpf__perf_for_each_map_named(map, perf_obj, tmp, name) { - struct bpf_map_priv *priv = map_priv(map); - - if (IS_ERR(priv)) - return ERR_PTR(-BPF_LOADER_ERRNO__INTERNAL); - - /* - * No need to check map type: type should have been - * verified by kernel. - */ - if (!need_init && !priv) - need_init = !priv; - if (!tmpl_priv && priv) - tmpl_priv = priv; - } - - if (!need_init) - return NULL; - - if (!tmpl_priv) { - char *event_definition = NULL; - - if (asprintf(&event_definition, "bpf-output/no-inherit=1,name=%s/", name) < 0) - return ERR_PTR(-ENOMEM); - - err = parse_event(evlist, event_definition); - free(event_definition); - - if (err) { - pr_debug("ERROR: failed to create the \"%s\" bpf-output event\n", name); - return ERR_PTR(-err); - } - - evsel = evlist__last(evlist); - } - - bpf__perf_for_each_map_named(map, perf_obj, tmp, name) { - struct bpf_map_priv *priv = map_priv(map); - - if (IS_ERR(priv)) - return ERR_PTR(-BPF_LOADER_ERRNO__INTERNAL); - if (priv) - continue; - - if (tmpl_priv) { - priv = bpf_map_priv__clone(tmpl_priv); - if (!priv) - return ERR_PTR(-ENOMEM); - - err = map_set_priv(map, priv); - if (err) { - bpf_map_priv__clear(map, priv); - return ERR_PTR(err); - } - } else if (evsel) { - struct bpf_map_op *op; - - op = bpf_map__add_newop(map, NULL); - if (IS_ERR(op)) - return ERR_CAST(op); - op->op_type = BPF_MAP_OP_SET_EVSEL; - op->v.evsel = evsel; - } - } - - return evsel; -} - -int bpf__setup_stdout(struct evlist *evlist) -{ - struct evsel *evsel = bpf__setup_output_event(evlist, "__bpf_stdout__"); - return PTR_ERR_OR_ZERO(evsel); -} - -#define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START) -#define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c) -#define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START) - -static const char *bpf_loader_strerror_table[NR_ERRNO] = { - [ERRCODE_OFFSET(CONFIG)] = "Invalid config string", - [ERRCODE_OFFSET(GROUP)] = "Invalid group name", - [ERRCODE_OFFSET(EVENTNAME)] = "No event name found in config string", - [ERRCODE_OFFSET(INTERNAL)] = "BPF loader internal error", - [ERRCODE_OFFSET(COMPILE)] = "Error when compiling BPF scriptlet", - [ERRCODE_OFFSET(PROGCONF_TERM)] = "Invalid program config term in config string", - [ERRCODE_OFFSET(PROLOGUE)] = "Failed to generate prologue", - [ERRCODE_OFFSET(PROLOGUE2BIG)] = "Prologue too big for program", - [ERRCODE_OFFSET(PROLOGUEOOB)] = "Offset out of bound for prologue", - [ERRCODE_OFFSET(OBJCONF_OPT)] = "Invalid object config option", - [ERRCODE_OFFSET(OBJCONF_CONF)] = "Config value not set (missing '=')", - [ERRCODE_OFFSET(OBJCONF_MAP_OPT)] = "Invalid object map config option", - [ERRCODE_OFFSET(OBJCONF_MAP_NOTEXIST)] = "Target map doesn't exist", - [ERRCODE_OFFSET(OBJCONF_MAP_VALUE)] = "Incorrect value type for map", - [ERRCODE_OFFSET(OBJCONF_MAP_TYPE)] = "Incorrect map type", - [ERRCODE_OFFSET(OBJCONF_MAP_KEYSIZE)] = "Incorrect map key size", - [ERRCODE_OFFSET(OBJCONF_MAP_VALUESIZE)] = "Incorrect map value size", - [ERRCODE_OFFSET(OBJCONF_MAP_NOEVT)] = "Event not found for map setting", - [ERRCODE_OFFSET(OBJCONF_MAP_MAPSIZE)] = "Invalid map size for event setting", - [ERRCODE_OFFSET(OBJCONF_MAP_EVTDIM)] = "Event dimension too large", - [ERRCODE_OFFSET(OBJCONF_MAP_EVTINH)] = "Doesn't support inherit event", - [ERRCODE_OFFSET(OBJCONF_MAP_EVTTYPE)] = "Wrong event type for map", - [ERRCODE_OFFSET(OBJCONF_MAP_IDX2BIG)] = "Index too large", -}; - -static int -bpf_loader_strerror(int err, char *buf, size_t size) -{ - char sbuf[STRERR_BUFSIZE]; - const char *msg; - - if (!buf || !size) - return -1; - - err = err > 0 ? err : -err; - - if (err >= __LIBBPF_ERRNO__START) - return libbpf_strerror(err, buf, size); - - if (err >= __BPF_LOADER_ERRNO__START && err < __BPF_LOADER_ERRNO__END) { - msg = bpf_loader_strerror_table[ERRNO_OFFSET(err)]; - snprintf(buf, size, "%s", msg); - buf[size - 1] = '\0'; - return 0; - } - - if (err >= __BPF_LOADER_ERRNO__END) - snprintf(buf, size, "Unknown bpf loader error %d", err); - else - snprintf(buf, size, "%s", - str_error_r(err, sbuf, sizeof(sbuf))); - - buf[size - 1] = '\0'; - return -1; -} - -#define bpf__strerror_head(err, buf, size) \ - char sbuf[STRERR_BUFSIZE], *emsg;\ - if (!size)\ - return 0;\ - if (err < 0)\ - err = -err;\ - bpf_loader_strerror(err, sbuf, sizeof(sbuf));\ - emsg = sbuf;\ - switch (err) {\ - default:\ - scnprintf(buf, size, "%s", emsg);\ - break; - -#define bpf__strerror_entry(val, fmt...)\ - case val: {\ - scnprintf(buf, size, fmt);\ - break;\ - } - -#define bpf__strerror_end(buf, size)\ - }\ - buf[size - 1] = '\0'; - -int bpf__strerror_prepare_load(const char *filename, bool source, - int err, char *buf, size_t size) -{ - size_t n; - int ret; - - n = snprintf(buf, size, "Failed to load %s%s: ", - filename, source ? " from source" : ""); - if (n >= size) { - buf[size - 1] = '\0'; - return 0; - } - buf += n; - size -= n; - - ret = bpf_loader_strerror(err, buf, size); - buf[size - 1] = '\0'; - return ret; -} - -int bpf__strerror_probe(struct bpf_object *obj __maybe_unused, - int err, char *buf, size_t size) -{ - bpf__strerror_head(err, buf, size); - case BPF_LOADER_ERRNO__PROGCONF_TERM: { - scnprintf(buf, size, "%s (add -v to see detail)", emsg); - break; - } - bpf__strerror_entry(EEXIST, "Probe point exist. Try 'perf probe -d \"*\"' and set 'force=yes'"); - bpf__strerror_entry(EACCES, "You need to be root"); - bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0"); - bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file"); - bpf__strerror_end(buf, size); - return 0; -} - -int bpf__strerror_load(struct bpf_object *obj, - int err, char *buf, size_t size) -{ - bpf__strerror_head(err, buf, size); - case LIBBPF_ERRNO__KVER: { - unsigned int obj_kver = bpf_object__kversion(obj); - unsigned int real_kver; - - if (fetch_kernel_version(&real_kver, NULL, 0)) { - scnprintf(buf, size, "Unable to fetch kernel version"); - break; - } - - if (obj_kver != real_kver) { - scnprintf(buf, size, - "'version' ("KVER_FMT") doesn't match running kernel ("KVER_FMT")", - KVER_PARAM(obj_kver), - KVER_PARAM(real_kver)); - break; - } - - scnprintf(buf, size, "Failed to load program for unknown reason"); - break; - } - bpf__strerror_end(buf, size); - return 0; -} - -int bpf__strerror_config_obj(struct bpf_object *obj __maybe_unused, - struct parse_events_term *term __maybe_unused, - struct evlist *evlist __maybe_unused, - int *error_pos __maybe_unused, int err, - char *buf, size_t size) -{ - bpf__strerror_head(err, buf, size); - bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE, - "Can't use this config term with this map type"); - bpf__strerror_end(buf, size); - return 0; -} - -int bpf__strerror_apply_obj_config(int err, char *buf, size_t size) -{ - bpf__strerror_head(err, buf, size); - bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM, - "Cannot set event to BPF map in multi-thread tracing"); - bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH, - "%s (Hint: use -i to turn off inherit)", emsg); - bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE, - "Can only put raw, hardware and BPF output event into a BPF map"); - bpf__strerror_end(buf, size); - return 0; -} - -int bpf__strerror_setup_output_event(struct evlist *evlist __maybe_unused, - int err, char *buf, size_t size) -{ - bpf__strerror_head(err, buf, size); - bpf__strerror_end(buf, size); - return 0; -} diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h deleted file mode 100644 index 5d1c725cea295..0000000000000 --- a/tools/perf/util/bpf-loader.h +++ /dev/null @@ -1,216 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2015, Wang Nan - * Copyright (C) 2015, Huawei Inc. - */ -#ifndef __BPF_LOADER_H -#define __BPF_LOADER_H - -#include -#include - -#ifdef HAVE_LIBBPF_SUPPORT -#include - -enum bpf_loader_errno { - __BPF_LOADER_ERRNO__START = __LIBBPF_ERRNO__START - 100, - /* Invalid config string */ - BPF_LOADER_ERRNO__CONFIG = __BPF_LOADER_ERRNO__START, - BPF_LOADER_ERRNO__GROUP, /* Invalid group name */ - BPF_LOADER_ERRNO__EVENTNAME, /* Event name is missing */ - BPF_LOADER_ERRNO__INTERNAL, /* BPF loader internal error */ - BPF_LOADER_ERRNO__COMPILE, /* Error when compiling BPF scriptlet */ - BPF_LOADER_ERRNO__PROGCONF_TERM,/* Invalid program config term in config string */ - BPF_LOADER_ERRNO__PROLOGUE, /* Failed to generate prologue */ - BPF_LOADER_ERRNO__PROLOGUE2BIG, /* Prologue too big for program */ - BPF_LOADER_ERRNO__PROLOGUEOOB, /* Offset out of bound for prologue */ - BPF_LOADER_ERRNO__OBJCONF_OPT, /* Invalid object config option */ - BPF_LOADER_ERRNO__OBJCONF_CONF, /* Config value not set (lost '=')) */ - BPF_LOADER_ERRNO__OBJCONF_MAP_OPT, /* Invalid object map config option */ - BPF_LOADER_ERRNO__OBJCONF_MAP_NOTEXIST, /* Target map not exist */ - BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE, /* Incorrect value type for map */ - BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE, /* Incorrect map type */ - BPF_LOADER_ERRNO__OBJCONF_MAP_KEYSIZE, /* Incorrect map key size */ - BPF_LOADER_ERRNO__OBJCONF_MAP_VALUESIZE,/* Incorrect map value size */ - BPF_LOADER_ERRNO__OBJCONF_MAP_NOEVT, /* Event not found for map setting */ - BPF_LOADER_ERRNO__OBJCONF_MAP_MAPSIZE, /* Invalid map size for event setting */ - BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM, /* Event dimension too large */ - BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH, /* Doesn't support inherit event */ - BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE, /* Wrong event type for map */ - BPF_LOADER_ERRNO__OBJCONF_MAP_IDX2BIG, /* Index too large */ - __BPF_LOADER_ERRNO__END, -}; -#endif // HAVE_LIBBPF_SUPPORT - -struct evsel; -struct evlist; -struct bpf_object; -struct parse_events_term; -#define PERF_BPF_PROBE_GROUP "perf_bpf_probe" - -typedef int (*bpf_prog_iter_callback_t)(const char *group, const char *event, - int fd, struct bpf_object *obj, void *arg); - -#ifdef HAVE_LIBBPF_SUPPORT -struct bpf_object *bpf__prepare_load(const char *filename, bool source); -int bpf__strerror_prepare_load(const char *filename, bool source, - int err, char *buf, size_t size); - -struct bpf_object *bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz, - const char *name); - -void bpf__clear(void); - -int bpf__probe(struct bpf_object *obj); -int bpf__unprobe(struct bpf_object *obj); -int bpf__strerror_probe(struct bpf_object *obj, int err, - char *buf, size_t size); - -int bpf__load(struct bpf_object *obj); -int bpf__strerror_load(struct bpf_object *obj, int err, - char *buf, size_t size); -int bpf__foreach_event(struct bpf_object *obj, - bpf_prog_iter_callback_t func, void *arg); - -int bpf__config_obj(struct bpf_object *obj, struct parse_events_term *term, - struct evlist *evlist, int *error_pos); -int bpf__strerror_config_obj(struct bpf_object *obj, - struct parse_events_term *term, - struct evlist *evlist, - int *error_pos, int err, char *buf, - size_t size); -int bpf__apply_obj_config(void); -int bpf__strerror_apply_obj_config(int err, char *buf, size_t size); - -int bpf__setup_stdout(struct evlist *evlist); -struct evsel *bpf__setup_output_event(struct evlist *evlist, const char *name); -int bpf__strerror_setup_output_event(struct evlist *evlist, int err, char *buf, size_t size); -#else -#include -#include -#include "debug.h" - -static inline struct bpf_object * -bpf__prepare_load(const char *filename __maybe_unused, - bool source __maybe_unused) -{ - pr_debug("ERROR: eBPF object loading is disabled during compiling.\n"); - return ERR_PTR(-ENOTSUP); -} - -static inline struct bpf_object * -bpf__prepare_load_buffer(void *obj_buf __maybe_unused, - size_t obj_buf_sz __maybe_unused) -{ - return ERR_PTR(-ENOTSUP); -} - -static inline void bpf__clear(void) { } - -static inline int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;} -static inline int bpf__unprobe(struct bpf_object *obj __maybe_unused) { return 0;} -static inline int bpf__load(struct bpf_object *obj __maybe_unused) { return 0; } - -static inline int -bpf__foreach_event(struct bpf_object *obj __maybe_unused, - bpf_prog_iter_callback_t func __maybe_unused, - void *arg __maybe_unused) -{ - return 0; -} - -static inline int -bpf__config_obj(struct bpf_object *obj __maybe_unused, - struct parse_events_term *term __maybe_unused, - struct evlist *evlist __maybe_unused, - int *error_pos __maybe_unused) -{ - return 0; -} - -static inline int -bpf__apply_obj_config(void) -{ - return 0; -} - -static inline int -bpf__setup_stdout(struct evlist *evlist __maybe_unused) -{ - return 0; -} - -static inline struct evsel * -bpf__setup_output_event(struct evlist *evlist __maybe_unused, const char *name __maybe_unused) -{ - return NULL; -} - -static inline int -__bpf_strerror(char *buf, size_t size) -{ - if (!size) - return 0; - strncpy(buf, - "ERROR: eBPF object loading is disabled during compiling.\n", - size); - buf[size - 1] = '\0'; - return 0; -} - -static inline -int bpf__strerror_prepare_load(const char *filename __maybe_unused, - bool source __maybe_unused, - int err __maybe_unused, - char *buf, size_t size) -{ - return __bpf_strerror(buf, size); -} - -static inline int -bpf__strerror_probe(struct bpf_object *obj __maybe_unused, - int err __maybe_unused, - char *buf, size_t size) -{ - return __bpf_strerror(buf, size); -} - -static inline int bpf__strerror_load(struct bpf_object *obj __maybe_unused, - int err __maybe_unused, - char *buf, size_t size) -{ - return __bpf_strerror(buf, size); -} - -static inline int -bpf__strerror_config_obj(struct bpf_object *obj __maybe_unused, - struct parse_events_term *term __maybe_unused, - struct evlist *evlist __maybe_unused, - int *error_pos __maybe_unused, - int err __maybe_unused, - char *buf, size_t size) -{ - return __bpf_strerror(buf, size); -} - -static inline int -bpf__strerror_apply_obj_config(int err __maybe_unused, - char *buf, size_t size) -{ - return __bpf_strerror(buf, size); -} - -static inline int -bpf__strerror_setup_output_event(struct evlist *evlist __maybe_unused, - int err __maybe_unused, char *buf, size_t size) -{ - return __bpf_strerror(buf, size); -} - -#endif - -static inline int bpf__strerror_setup_stdout(struct evlist *evlist, int err, char *buf, size_t size) -{ - return bpf__strerror_setup_output_event(evlist, err, buf, size); -} -#endif diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 46f144c468279..7a650de0db83f 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -16,7 +16,6 @@ #include #include "util/event.h" /* proc_map_timeout */ #include "util/hist.h" /* perf_hist_config */ -#include "util/llvm-utils.h" /* perf_llvm_config */ #include "util/stat.h" /* perf_stat__set_big_num */ #include "util/evsel.h" /* evsel__hw_names, evsel__use_bpf_counters */ #include "util/srcline.h" /* addr2line_timeout_ms */ @@ -486,9 +485,6 @@ int perf_default_config(const char *var, const char *value, if (strstarts(var, "call-graph.")) return perf_callchain_config(var, value); - if (strstarts(var, "llvm.")) - return perf_llvm_config(var, value); - if (strstarts(var, "buildid.")) return perf_buildid_config(var, value); diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c deleted file mode 100644 index c6c9c22285787..0000000000000 --- a/tools/perf/util/llvm-utils.c +++ /dev/null @@ -1,612 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2015, Wang Nan - * Copyright (C) 2015, Huawei Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "debug.h" -#include "llvm-utils.h" -#include "config.h" -#include "util.h" -#include -#include - -#define CLANG_BPF_CMD_DEFAULT_TEMPLATE \ - "$CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS "\ - "-DLINUX_VERSION_CODE=$LINUX_VERSION_CODE " \ - "$CLANG_OPTIONS $PERF_BPF_INC_OPTIONS $KERNEL_INC_OPTIONS " \ - "-Wno-unused-value -Wno-pointer-sign " \ - "-working-directory $WORKING_DIR " \ - "-c \"$CLANG_SOURCE\" --target=bpf $CLANG_EMIT_LLVM -g -O2 -o - $LLVM_OPTIONS_PIPE" - -struct llvm_param llvm_param = { - .clang_path = "clang", - .llc_path = "llc", - .clang_bpf_cmd_template = CLANG_BPF_CMD_DEFAULT_TEMPLATE, - .clang_opt = NULL, - .opts = NULL, - .kbuild_dir = NULL, - .kbuild_opts = NULL, - .user_set_param = false, -}; - -static void version_notice(void); - -int perf_llvm_config(const char *var, const char *value) -{ - if (!strstarts(var, "llvm.")) - return 0; - var += sizeof("llvm.") - 1; - - if (!strcmp(var, "clang-path")) - llvm_param.clang_path = strdup(value); - else if (!strcmp(var, "clang-bpf-cmd-template")) - llvm_param.clang_bpf_cmd_template = strdup(value); - else if (!strcmp(var, "clang-opt")) - llvm_param.clang_opt = strdup(value); - else if (!strcmp(var, "kbuild-dir")) - llvm_param.kbuild_dir = strdup(value); - else if (!strcmp(var, "kbuild-opts")) - llvm_param.kbuild_opts = strdup(value); - else if (!strcmp(var, "dump-obj")) - llvm_param.dump_obj = !!perf_config_bool(var, value); - else if (!strcmp(var, "opts")) - llvm_param.opts = strdup(value); - else { - pr_debug("Invalid LLVM config option: %s\n", value); - return -1; - } - llvm_param.user_set_param = true; - return 0; -} - -static int -search_program(const char *def, const char *name, - char *output) -{ - char *env, *path, *tmp = NULL; - char buf[PATH_MAX]; - int ret; - - output[0] = '\0'; - if (def && def[0] != '\0') { - if (def[0] == '/') { - if (access(def, F_OK) == 0) { - strlcpy(output, def, PATH_MAX); - return 0; - } - } else if (def[0] != '\0') - name = def; - } - - env = getenv("PATH"); - if (!env) - return -1; - env = strdup(env); - if (!env) - return -1; - - ret = -ENOENT; - path = strtok_r(env, ":", &tmp); - while (path) { - scnprintf(buf, sizeof(buf), "%s/%s", path, name); - if (access(buf, F_OK) == 0) { - strlcpy(output, buf, PATH_MAX); - ret = 0; - break; - } - path = strtok_r(NULL, ":", &tmp); - } - - free(env); - return ret; -} - -static int search_program_and_warn(const char *def, const char *name, - char *output) -{ - int ret = search_program(def, name, output); - - if (ret) { - pr_err("ERROR:\tunable to find %s.\n" - "Hint:\tTry to install latest clang/llvm to support BPF. Check your $PATH\n" - " \tand '%s-path' option in [llvm] section of ~/.perfconfig.\n", - name, name); - version_notice(); - } - return ret; -} - -#define READ_SIZE 4096 -static int -read_from_pipe(const char *cmd, void **p_buf, size_t *p_read_sz) -{ - int err = 0; - void *buf = NULL; - FILE *file = NULL; - size_t read_sz = 0, buf_sz = 0; - char serr[STRERR_BUFSIZE]; - - file = popen(cmd, "r"); - if (!file) { - pr_err("ERROR: unable to popen cmd: %s\n", - str_error_r(errno, serr, sizeof(serr))); - return -EINVAL; - } - - while (!feof(file) && !ferror(file)) { - /* - * Make buf_sz always have obe byte extra space so we - * can put '\0' there. - */ - if (buf_sz - read_sz < READ_SIZE + 1) { - void *new_buf; - - buf_sz = read_sz + READ_SIZE + 1; - new_buf = realloc(buf, buf_sz); - - if (!new_buf) { - pr_err("ERROR: failed to realloc memory\n"); - err = -ENOMEM; - goto errout; - } - - buf = new_buf; - } - read_sz += fread(buf + read_sz, 1, READ_SIZE, file); - } - - if (buf_sz - read_sz < 1) { - pr_err("ERROR: internal error\n"); - err = -EINVAL; - goto errout; - } - - if (ferror(file)) { - pr_err("ERROR: error occurred when reading from pipe: %s\n", - str_error_r(errno, serr, sizeof(serr))); - err = -EIO; - goto errout; - } - - err = WEXITSTATUS(pclose(file)); - file = NULL; - if (err) { - err = -EINVAL; - goto errout; - } - - /* - * If buf is string, give it terminal '\0' to make our life - * easier. If buf is not string, that '\0' is out of space - * indicated by read_sz so caller won't even notice it. - */ - ((char *)buf)[read_sz] = '\0'; - - if (!p_buf) - free(buf); - else - *p_buf = buf; - - if (p_read_sz) - *p_read_sz = read_sz; - return 0; - -errout: - if (file) - pclose(file); - free(buf); - if (p_buf) - *p_buf = NULL; - if (p_read_sz) - *p_read_sz = 0; - return err; -} - -static inline void -force_set_env(const char *var, const char *value) -{ - if (value) { - setenv(var, value, 1); - pr_debug("set env: %s=%s\n", var, value); - } else { - unsetenv(var); - pr_debug("unset env: %s\n", var); - } -} - -static void -version_notice(void) -{ - pr_err( -" \tLLVM 3.7 or newer is required. Which can be found from http://llvm.org\n" -" \tYou may want to try git trunk:\n" -" \t\tgit clone http://llvm.org/git/llvm.git\n" -" \t\t and\n" -" \t\tgit clone http://llvm.org/git/clang.git\n\n" -" \tOr fetch the latest clang/llvm 3.7 from pre-built llvm packages for\n" -" \tdebian/ubuntu:\n" -" \t\thttps://apt.llvm.org/\n\n" -" \tIf you are using old version of clang, change 'clang-bpf-cmd-template'\n" -" \toption in [llvm] section of ~/.perfconfig to:\n\n" -" \t \"$CLANG_EXEC $CLANG_OPTIONS $KERNEL_INC_OPTIONS $PERF_BPF_INC_OPTIONS \\\n" -" \t -working-directory $WORKING_DIR -c $CLANG_SOURCE \\\n" -" \t -emit-llvm -o - | /path/to/llc -march=bpf -filetype=obj -o -\"\n" -" \t(Replace /path/to/llc with path to your llc)\n\n" -); -} - -static int detect_kbuild_dir(char **kbuild_dir) -{ - const char *test_dir = llvm_param.kbuild_dir; - const char *prefix_dir = ""; - const char *suffix_dir = ""; - - /* _UTSNAME_LENGTH is 65 */ - char release[128]; - - char *autoconf_path; - - int err; - - if (!test_dir) { - err = fetch_kernel_version(NULL, release, - sizeof(release)); - if (err) - return -EINVAL; - - test_dir = release; - prefix_dir = "/lib/modules/"; - suffix_dir = "/build"; - } - - err = asprintf(&autoconf_path, "%s%s%s/include/generated/autoconf.h", - prefix_dir, test_dir, suffix_dir); - if (err < 0) - return -ENOMEM; - - if (access(autoconf_path, R_OK) == 0) { - free(autoconf_path); - - err = asprintf(kbuild_dir, "%s%s%s", prefix_dir, test_dir, - suffix_dir); - if (err < 0) - return -ENOMEM; - return 0; - } - pr_debug("%s: Couldn't find \"%s\", missing kernel-devel package?.\n", - __func__, autoconf_path); - free(autoconf_path); - return -ENOENT; -} - -static const char *kinc_fetch_script = -"#!/usr/bin/env sh\n" -"if ! test -d \"$KBUILD_DIR\"\n" -"then\n" -" exit 1\n" -"fi\n" -"if ! test -f \"$KBUILD_DIR/include/generated/autoconf.h\"\n" -"then\n" -" exit 1\n" -"fi\n" -"TMPDIR=`mktemp -d`\n" -"if test -z \"$TMPDIR\"\n" -"then\n" -" exit 1\n" -"fi\n" -"cat << EOF > $TMPDIR/Makefile\n" -"obj-y := dummy.o\n" -"\\$(obj)/%.o: \\$(src)/%.c\n" -"\t@echo -n \"\\$(NOSTDINC_FLAGS) \\$(LINUXINCLUDE) \\$(EXTRA_CFLAGS)\"\n" -"\t\\$(CC) -c -o \\$@ \\$<\n" -"EOF\n" -"touch $TMPDIR/dummy.c\n" -"make -s -C $KBUILD_DIR M=$TMPDIR $KBUILD_OPTS dummy.o 2>/dev/null\n" -"RET=$?\n" -"rm -rf $TMPDIR\n" -"exit $RET\n"; - -void llvm__get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts) -{ - static char *saved_kbuild_dir; - static char *saved_kbuild_include_opts; - int err; - - if (!kbuild_dir || !kbuild_include_opts) - return; - - *kbuild_dir = NULL; - *kbuild_include_opts = NULL; - - if (saved_kbuild_dir && saved_kbuild_include_opts && - !IS_ERR(saved_kbuild_dir) && !IS_ERR(saved_kbuild_include_opts)) { - *kbuild_dir = strdup(saved_kbuild_dir); - *kbuild_include_opts = strdup(saved_kbuild_include_opts); - - if (*kbuild_dir && *kbuild_include_opts) - return; - - zfree(kbuild_dir); - zfree(kbuild_include_opts); - /* - * Don't fall through: it may breaks saved_kbuild_dir and - * saved_kbuild_include_opts if detect them again when - * memory is low. - */ - return; - } - - if (llvm_param.kbuild_dir && !llvm_param.kbuild_dir[0]) { - pr_debug("[llvm.kbuild-dir] is set to \"\" deliberately.\n"); - pr_debug("Skip kbuild options detection.\n"); - goto errout; - } - - err = detect_kbuild_dir(kbuild_dir); - if (err) { - pr_warning( -"WARNING:\tunable to get correct kernel building directory.\n" -"Hint:\tSet correct kbuild directory using 'kbuild-dir' option in [llvm]\n" -" \tsection of ~/.perfconfig or set it to \"\" to suppress kbuild\n" -" \tdetection.\n\n"); - goto errout; - } - - pr_debug("Kernel build dir is set to %s\n", *kbuild_dir); - force_set_env("KBUILD_DIR", *kbuild_dir); - force_set_env("KBUILD_OPTS", llvm_param.kbuild_opts); - err = read_from_pipe(kinc_fetch_script, - (void **)kbuild_include_opts, - NULL); - if (err) { - pr_warning( -"WARNING:\tunable to get kernel include directories from '%s'\n" -"Hint:\tTry set clang include options using 'clang-bpf-cmd-template'\n" -" \toption in [llvm] section of ~/.perfconfig and set 'kbuild-dir'\n" -" \toption in [llvm] to \"\" to suppress this detection.\n\n", - *kbuild_dir); - - zfree(kbuild_dir); - goto errout; - } - - pr_debug("include option is set to %s\n", *kbuild_include_opts); - - saved_kbuild_dir = strdup(*kbuild_dir); - saved_kbuild_include_opts = strdup(*kbuild_include_opts); - - if (!saved_kbuild_dir || !saved_kbuild_include_opts) { - zfree(&saved_kbuild_dir); - zfree(&saved_kbuild_include_opts); - } - return; -errout: - saved_kbuild_dir = ERR_PTR(-EINVAL); - saved_kbuild_include_opts = ERR_PTR(-EINVAL); -} - -int llvm__get_nr_cpus(void) -{ - static int nr_cpus_avail = 0; - char serr[STRERR_BUFSIZE]; - - if (nr_cpus_avail > 0) - return nr_cpus_avail; - - nr_cpus_avail = sysconf(_SC_NPROCESSORS_CONF); - if (nr_cpus_avail <= 0) { - pr_err( -"WARNING:\tunable to get available CPUs in this system: %s\n" -" \tUse 128 instead.\n", str_error_r(errno, serr, sizeof(serr))); - nr_cpus_avail = 128; - } - return nr_cpus_avail; -} - -void llvm__dump_obj(const char *path, void *obj_buf, size_t size) -{ - char *obj_path = strdup(path); - FILE *fp; - char *p; - - if (!obj_path) { - pr_warning("WARNING: Not enough memory, skip object dumping\n"); - return; - } - - p = strrchr(obj_path, '.'); - if (!p || (strcmp(p, ".c") != 0)) { - pr_warning("WARNING: invalid llvm source path: '%s', skip object dumping\n", - obj_path); - goto out; - } - - p[1] = 'o'; - fp = fopen(obj_path, "wb"); - if (!fp) { - pr_warning("WARNING: failed to open '%s': %s, skip object dumping\n", - obj_path, strerror(errno)); - goto out; - } - - pr_debug("LLVM: dumping %s\n", obj_path); - if (fwrite(obj_buf, size, 1, fp) != 1) - pr_debug("WARNING: failed to write to file '%s': %s, skip object dumping\n", obj_path, strerror(errno)); - fclose(fp); -out: - free(obj_path); -} - -int llvm__compile_bpf(const char *path, void **p_obj_buf, - size_t *p_obj_buf_sz) -{ - size_t obj_buf_sz; - void *obj_buf = NULL; - int err, nr_cpus_avail; - unsigned int kernel_version; - char linux_version_code_str[64]; - const char *clang_opt = llvm_param.clang_opt; - char clang_path[PATH_MAX], llc_path[PATH_MAX], abspath[PATH_MAX], nr_cpus_avail_str[64]; - char serr[STRERR_BUFSIZE]; - char *kbuild_dir = NULL, *kbuild_include_opts = NULL, - *perf_bpf_include_opts = NULL; - const char *template = llvm_param.clang_bpf_cmd_template; - char *pipe_template = NULL; - const char *opts = llvm_param.opts; - char *command_echo = NULL, *command_out; - char *libbpf_include_dir = system_path(LIBBPF_INCLUDE_DIR); - - if (path[0] != '-' && realpath(path, abspath) == NULL) { - err = errno; - pr_err("ERROR: problems with path %s: %s\n", - path, str_error_r(err, serr, sizeof(serr))); - return -err; - } - - if (!template) - template = CLANG_BPF_CMD_DEFAULT_TEMPLATE; - - err = search_program_and_warn(llvm_param.clang_path, - "clang", clang_path); - if (err) - return -ENOENT; - - /* - * This is an optional work. Even it fail we can continue our - * work. Needn't check error return. - */ - llvm__get_kbuild_opts(&kbuild_dir, &kbuild_include_opts); - - nr_cpus_avail = llvm__get_nr_cpus(); - snprintf(nr_cpus_avail_str, sizeof(nr_cpus_avail_str), "%d", - nr_cpus_avail); - - if (fetch_kernel_version(&kernel_version, NULL, 0)) - kernel_version = 0; - - snprintf(linux_version_code_str, sizeof(linux_version_code_str), - "0x%x", kernel_version); - if (asprintf(&perf_bpf_include_opts, "-I%s/", libbpf_include_dir) < 0) - goto errout; - force_set_env("NR_CPUS", nr_cpus_avail_str); - force_set_env("LINUX_VERSION_CODE", linux_version_code_str); - force_set_env("CLANG_EXEC", clang_path); - force_set_env("CLANG_OPTIONS", clang_opt); - force_set_env("KERNEL_INC_OPTIONS", kbuild_include_opts); - force_set_env("PERF_BPF_INC_OPTIONS", perf_bpf_include_opts); - force_set_env("WORKING_DIR", kbuild_dir ? : "."); - - if (opts) { - err = search_program_and_warn(llvm_param.llc_path, "llc", llc_path); - if (err) - goto errout; - - err = -ENOMEM; - if (asprintf(&pipe_template, "%s -emit-llvm | %s -march=bpf %s -filetype=obj -o -", - template, llc_path, opts) < 0) { - pr_err("ERROR:\tnot enough memory to setup command line\n"); - goto errout; - } - - template = pipe_template; - - } - - /* - * Since we may reset clang's working dir, path of source file - * should be transferred into absolute path, except we want - * stdin to be source file (testing). - */ - force_set_env("CLANG_SOURCE", - (path[0] == '-') ? path : abspath); - - pr_debug("llvm compiling command template: %s\n", template); - - /* - * Below, substitute control characters for values that can cause the - * echo to misbehave, then substitute the values back. - */ - err = -ENOMEM; - if (asprintf(&command_echo, "echo -n \a%s\a", template) < 0) - goto errout; - -#define SWAP_CHAR(a, b) do { if (*p == a) *p = b; } while (0) - for (char *p = command_echo; *p; p++) { - SWAP_CHAR('<', '\001'); - SWAP_CHAR('>', '\002'); - SWAP_CHAR('"', '\003'); - SWAP_CHAR('\'', '\004'); - SWAP_CHAR('|', '\005'); - SWAP_CHAR('&', '\006'); - SWAP_CHAR('\a', '"'); - } - err = read_from_pipe(command_echo, (void **) &command_out, NULL); - if (err) - goto errout; - - for (char *p = command_out; *p; p++) { - SWAP_CHAR('\001', '<'); - SWAP_CHAR('\002', '>'); - SWAP_CHAR('\003', '"'); - SWAP_CHAR('\004', '\''); - SWAP_CHAR('\005', '|'); - SWAP_CHAR('\006', '&'); - } -#undef SWAP_CHAR - pr_debug("llvm compiling command : %s\n", command_out); - - err = read_from_pipe(template, &obj_buf, &obj_buf_sz); - if (err) { - pr_err("ERROR:\tunable to compile %s\n", path); - pr_err("Hint:\tCheck error message shown above.\n"); - pr_err("Hint:\tYou can also pre-compile it into .o using:\n"); - pr_err(" \t\tclang --target=bpf -O2 -c %s\n", path); - pr_err(" \twith proper -I and -D options.\n"); - goto errout; - } - - free(command_echo); - free(command_out); - free(kbuild_dir); - free(kbuild_include_opts); - free(perf_bpf_include_opts); - free(libbpf_include_dir); - - if (!p_obj_buf) - free(obj_buf); - else - *p_obj_buf = obj_buf; - - if (p_obj_buf_sz) - *p_obj_buf_sz = obj_buf_sz; - return 0; -errout: - free(command_echo); - free(kbuild_dir); - free(kbuild_include_opts); - free(obj_buf); - free(perf_bpf_include_opts); - free(libbpf_include_dir); - free(pipe_template); - if (p_obj_buf) - *p_obj_buf = NULL; - if (p_obj_buf_sz) - *p_obj_buf_sz = 0; - return err; -} - -int llvm__search_clang(void) -{ - char clang_path[PATH_MAX]; - - return search_program_and_warn(llvm_param.clang_path, "clang", clang_path); -} diff --git a/tools/perf/util/llvm-utils.h b/tools/perf/util/llvm-utils.h deleted file mode 100644 index 7878a0e3fa983..0000000000000 --- a/tools/perf/util/llvm-utils.h +++ /dev/null @@ -1,69 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2015, Wang Nan - * Copyright (C) 2015, Huawei Inc. - */ -#ifndef __LLVM_UTILS_H -#define __LLVM_UTILS_H - -#include - -struct llvm_param { - /* Path of clang executable */ - const char *clang_path; - /* Path of llc executable */ - const char *llc_path; - /* - * Template of clang bpf compiling. 5 env variables - * can be used: - * $CLANG_EXEC: Path to clang. - * $CLANG_OPTIONS: Extra options to clang. - * $KERNEL_INC_OPTIONS: Kernel include directories. - * $WORKING_DIR: Kernel source directory. - * $CLANG_SOURCE: Source file to be compiled. - */ - const char *clang_bpf_cmd_template; - /* Will be filled in $CLANG_OPTIONS */ - const char *clang_opt; - /* - * If present it'll add -emit-llvm to $CLANG_OPTIONS to pipe - * the clang output to llc, useful for new llvm options not - * yet selectable via 'clang -mllvm option', such as -mattr=dwarfris - * in clang 6.0/llvm 7 - */ - const char *opts; - /* Where to find kbuild system */ - const char *kbuild_dir; - /* - * Arguments passed to make, like 'ARCH=arm' if doing cross - * compiling. Should not be used for dynamic compiling. - */ - const char *kbuild_opts; - /* - * Default is false. If set to true, write compiling result - * to object file. - */ - bool dump_obj; - /* - * Default is false. If one of the above fields is set by user - * explicitly then user_set_llvm is set to true. This is used - * for perf test. If user doesn't set anything in .perfconfig - * and clang is not found, don't trigger llvm test. - */ - bool user_set_param; -}; - -extern struct llvm_param llvm_param; -int perf_llvm_config(const char *var, const char *value); - -int llvm__compile_bpf(const char *path, void **p_obj_buf, size_t *p_obj_buf_sz); - -/* This function is for test__llvm() use only */ -int llvm__search_clang(void); - -/* Following functions are reused by builtin clang support */ -void llvm__get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts); -int llvm__get_nr_cpus(void); - -void llvm__dump_obj(const char *path, void *obj_buf, size_t size); -#endif diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 0b5075ef00c89..00a8ec94f5b28 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -14,7 +14,6 @@ #include "parse-events.h" #include "string2.h" #include "strlist.h" -#include "bpf-loader.h" #include "debug.h" #include #include @@ -648,272 +647,6 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx, } #endif /* HAVE_LIBTRACEEVENT */ -#ifdef HAVE_LIBBPF_SUPPORT -struct __add_bpf_event_param { - struct parse_events_state *parse_state; - struct list_head *list; - struct list_head *head_config; - YYLTYPE *loc; -}; - -static int add_bpf_event(const char *group, const char *event, int fd, struct bpf_object *obj, - void *_param) -{ - LIST_HEAD(new_evsels); - struct __add_bpf_event_param *param = _param; - struct parse_events_state *parse_state = param->parse_state; - struct list_head *list = param->list; - struct evsel *pos; - int err; - /* - * Check if we should add the event, i.e. if it is a TP but starts with a '!', - * then don't add the tracepoint, this will be used for something else, like - * adding to a BPF_MAP_TYPE_PROG_ARRAY. - * - * See tools/perf/examples/bpf/augmented_raw_syscalls.c - */ - if (group[0] == '!') - return 0; - - pr_debug("add bpf event %s:%s and attach bpf program %d\n", - group, event, fd); - - err = parse_events_add_tracepoint(&new_evsels, &parse_state->idx, group, - event, parse_state->error, - param->head_config, param->loc); - if (err) { - struct evsel *evsel, *tmp; - - pr_debug("Failed to add BPF event %s:%s\n", - group, event); - list_for_each_entry_safe(evsel, tmp, &new_evsels, core.node) { - list_del_init(&evsel->core.node); - evsel__delete(evsel); - } - return err; - } - pr_debug("adding %s:%s\n", group, event); - - list_for_each_entry(pos, &new_evsels, core.node) { - pr_debug("adding %s:%s to %p\n", - group, event, pos); - pos->bpf_fd = fd; - pos->bpf_obj = obj; - } - list_splice(&new_evsels, list); - return 0; -} - -int parse_events_load_bpf_obj(struct parse_events_state *parse_state, - struct list_head *list, - struct bpf_object *obj, - struct list_head *head_config, - void *loc) -{ - int err; - char errbuf[BUFSIZ]; - struct __add_bpf_event_param param = {parse_state, list, head_config, loc}; - static bool registered_unprobe_atexit = false; - YYLTYPE test_loc = {.first_column = -1}; - - if (IS_ERR(obj) || !obj) { - snprintf(errbuf, sizeof(errbuf), - "Internal error: load bpf obj with NULL"); - err = -EINVAL; - goto errout; - } - - /* - * Register atexit handler before calling bpf__probe() so - * bpf__probe() don't need to unprobe probe points its already - * created when failure. - */ - if (!registered_unprobe_atexit) { - atexit(bpf__clear); - registered_unprobe_atexit = true; - } - - err = bpf__probe(obj); - if (err) { - bpf__strerror_probe(obj, err, errbuf, sizeof(errbuf)); - goto errout; - } - - err = bpf__load(obj); - if (err) { - bpf__strerror_load(obj, err, errbuf, sizeof(errbuf)); - goto errout; - } - - if (!param.loc) - param.loc = &test_loc; - - err = bpf__foreach_event(obj, add_bpf_event, ¶m); - if (err) { - snprintf(errbuf, sizeof(errbuf), - "Attach events in BPF object failed"); - goto errout; - } - - return 0; -errout: - parse_events_error__handle(parse_state->error, param.loc ? param.loc->first_column : 0, - strdup(errbuf), strdup("(add -v to see detail)")); - return err; -} - -static int -parse_events_config_bpf(struct parse_events_state *parse_state, - struct bpf_object *obj, - struct list_head *head_config) -{ - struct parse_events_term *term; - int error_pos = 0; - - if (!head_config || list_empty(head_config)) - return 0; - - list_for_each_entry(term, head_config, list) { - int err; - - if (term->type_term != PARSE_EVENTS__TERM_TYPE_USER) { - parse_events_error__handle(parse_state->error, term->err_term, - strdup("Invalid config term for BPF object"), - NULL); - return -EINVAL; - } - - err = bpf__config_obj(obj, term, parse_state->evlist, &error_pos); - if (err) { - char errbuf[BUFSIZ]; - int idx; - - bpf__strerror_config_obj(obj, term, parse_state->evlist, - &error_pos, err, errbuf, - sizeof(errbuf)); - - if (err == -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE) - idx = term->err_val; - else - idx = term->err_term + error_pos; - - parse_events_error__handle(parse_state->error, idx, - strdup(errbuf), - NULL); - return err; - } - } - return 0; -} - -/* - * Split config terms: - * perf record -e bpf.c/call-graph=fp,map:array.value[0]=1/ ... - * 'call-graph=fp' is 'evt config', should be applied to each - * events in bpf.c. - * 'map:array.value[0]=1' is 'obj config', should be processed - * with parse_events_config_bpf. - * - * Move object config terms from the first list to obj_head_config. - */ -static void -split_bpf_config_terms(struct list_head *evt_head_config, - struct list_head *obj_head_config) -{ - struct parse_events_term *term, *temp; - - /* - * Currently, all possible user config term - * belong to bpf object. parse_events__is_hardcoded_term() - * happens to be a good flag. - * - * See parse_events_config_bpf() and - * config_term_tracepoint(). - */ - list_for_each_entry_safe(term, temp, evt_head_config, list) - if (!parse_events__is_hardcoded_term(term)) - list_move_tail(&term->list, obj_head_config); -} - -int parse_events_load_bpf(struct parse_events_state *parse_state, - struct list_head *list, - char *bpf_file_name, - bool source, - struct list_head *head_config, - void *loc_) -{ - int err; - struct bpf_object *obj; - LIST_HEAD(obj_head_config); - YYLTYPE *loc = loc_; - - if (head_config) - split_bpf_config_terms(head_config, &obj_head_config); - - obj = bpf__prepare_load(bpf_file_name, source); - if (IS_ERR(obj)) { - char errbuf[BUFSIZ]; - - err = PTR_ERR(obj); - - if (err == -ENOTSUP) - snprintf(errbuf, sizeof(errbuf), - "BPF support is not compiled"); - else - bpf__strerror_prepare_load(bpf_file_name, - source, - -err, errbuf, - sizeof(errbuf)); - - parse_events_error__handle(parse_state->error, loc->first_column, - strdup(errbuf), strdup("(add -v to see detail)")); - return err; - } - - err = parse_events_load_bpf_obj(parse_state, list, obj, head_config, loc); - if (err) - return err; - err = parse_events_config_bpf(parse_state, obj, &obj_head_config); - - /* - * Caller doesn't know anything about obj_head_config, - * so combine them together again before returning. - */ - if (head_config) - list_splice_tail(&obj_head_config, head_config); - return err; -} -#else // HAVE_LIBBPF_SUPPORT -int parse_events_load_bpf_obj(struct parse_events_state *parse_state, - struct list_head *list __maybe_unused, - struct bpf_object *obj __maybe_unused, - struct list_head *head_config __maybe_unused, - void *loc_) -{ - YYLTYPE *loc = loc_; - - parse_events_error__handle(parse_state->error, loc->first_column, - strdup("BPF support is not compiled"), - strdup("Make sure libbpf-devel is available at build time.")); - return -ENOTSUP; -} - -int parse_events_load_bpf(struct parse_events_state *parse_state, - struct list_head *list __maybe_unused, - char *bpf_file_name __maybe_unused, - bool source __maybe_unused, - struct list_head *head_config __maybe_unused, - void *loc_) -{ - YYLTYPE *loc = loc_; - - parse_events_error__handle(parse_state->error, loc->first_column, - strdup("BPF support is not compiled"), - strdup("Make sure libbpf-devel is available at build time.")); - return -ENOTSUP; -} -#endif // HAVE_LIBBPF_SUPPORT - static int parse_breakpoint_type(const char *type, struct perf_event_attr *attr) { @@ -2274,7 +2007,6 @@ int __parse_events(struct evlist *evlist, const char *str, const char *pmu_filte .list = LIST_HEAD_INIT(parse_state.list), .idx = evlist->core.nr_entries, .error = err, - .evlist = evlist, .stoken = PE_START_EVENTS, .fake_pmu = fake_pmu, .pmu_filter = pmu_filter, diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index b77ff619a6236..411f69b2ac3a9 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -118,8 +118,6 @@ struct parse_events_state { int idx; /* Error information. */ struct parse_events_error *error; - /* Used by BPF event creation. */ - struct evlist *evlist; /* Holds returned terms for term parsing. */ struct list_head *terms; /* Start token. */ @@ -160,19 +158,6 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx, const char *sys, const char *event, struct parse_events_error *error, struct list_head *head_config, void *loc); -int parse_events_load_bpf(struct parse_events_state *parse_state, - struct list_head *list, - char *bpf_file_name, - bool source, - struct list_head *head_config, - void *loc); -/* Provide this function for perf test */ -struct bpf_object; -int parse_events_load_bpf_obj(struct parse_events_state *parse_state, - struct list_head *list, - struct bpf_object *obj, - struct list_head *head_config, - void *loc); int parse_events_add_numeric(struct parse_events_state *parse_state, struct list_head *list, u32 type, u64 config, diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index d7d084cc4140d..1147084b2c767 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -68,31 +68,6 @@ static int lc_str(yyscan_t scanner, const struct parse_events_state *state) return str(scanner, state->match_legacy_cache_terms ? PE_LEGACY_CACHE : PE_NAME); } -static bool isbpf_suffix(char *text) -{ - int len = strlen(text); - - if (len < 2) - return false; - if ((text[len - 1] == 'c' || text[len - 1] == 'o') && - text[len - 2] == '.') - return true; - if (len > 4 && !strcmp(text + len - 4, ".obj")) - return true; - return false; -} - -static bool isbpf(yyscan_t scanner) -{ - char *text = parse_events_get_text(scanner); - struct stat st; - - if (!isbpf_suffix(text)) - return false; - - return stat(text, &st) == 0; -} - /* * This function is called when the parser gets two kind of input: * @@ -179,8 +154,6 @@ do { \ group [^,{}/]*[{][^}]*[}][^,{}/]* event_pmu [^,{}/]+[/][^/]*[/][^,{}/]* event [^,{}/]+ -bpf_object [^,{}]+\.(o|bpf)[a-zA-Z0-9._]* -bpf_source [^,{}]+\.c[a-zA-Z0-9._]* num_dec [0-9]+ num_hex 0x[a-fA-F0-9]+ @@ -233,8 +206,6 @@ non_digit [^0-9] } {event_pmu} | -{bpf_object} | -{bpf_source} | {event} { BEGIN(INITIAL); REWIND(1); @@ -363,8 +334,6 @@ r{num_raw_hex} { return str(yyscanner, PE_RAW); } {num_hex} { return value(yyscanner, 16); } {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } -{bpf_object} { if (!isbpf(yyscanner)) { USER_REJECT }; return str(yyscanner, PE_BPF_OBJECT); } -{bpf_source} { if (!isbpf(yyscanner)) { USER_REJECT }; return str(yyscanner, PE_BPF_SOURCE); } {name} { return str(yyscanner, PE_NAME); } {name_tag} { return str(yyscanner, PE_NAME); } "/" { BEGIN(config); return '/'; } diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index c3517e3498d7b..00da1f8c0baf1 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -60,7 +60,6 @@ static void free_list_evsel(struct list_head* list_evsel) %token PE_VALUE_SYM_TOOL %token PE_EVENT_NAME %token PE_RAW PE_NAME -%token PE_BPF_OBJECT PE_BPF_SOURCE %token PE_MODIFIER_EVENT PE_MODIFIER_BP PE_BP_COLON PE_BP_SLASH %token PE_LEGACY_CACHE %token PE_PREFIX_MEM @@ -75,8 +74,6 @@ static void free_list_evsel(struct list_head* list_evsel) %type value_sym %type PE_RAW %type PE_NAME -%type PE_BPF_OBJECT -%type PE_BPF_SOURCE %type PE_LEGACY_CACHE %type PE_MODIFIER_EVENT %type PE_MODIFIER_BP @@ -97,7 +94,6 @@ static void free_list_evsel(struct list_head* list_evsel) %type event_legacy_tracepoint %type event_legacy_numeric %type event_legacy_raw -%type event_bpf_file %type event_def %type event_mod %type event_name @@ -271,8 +267,7 @@ event_def: event_pmu | event_legacy_mem sep_dc | event_legacy_tracepoint sep_dc | event_legacy_numeric sep_dc | - event_legacy_raw sep_dc | - event_bpf_file + event_legacy_raw sep_dc event_pmu: PE_NAME opt_pmu_config @@ -620,43 +615,6 @@ PE_RAW opt_event_config $$ = list; } -event_bpf_file: -PE_BPF_OBJECT opt_event_config -{ - struct parse_events_state *parse_state = _parse_state; - struct list_head *list; - int err; - - list = alloc_list(); - if (!list) - YYNOMEM; - err = parse_events_load_bpf(parse_state, list, $1, false, $2, &@1); - parse_events_terms__delete($2); - free($1); - if (err) { - free(list); - PE_ABORT(err); - } - $$ = list; -} -| -PE_BPF_SOURCE opt_event_config -{ - struct list_head *list; - int err; - - list = alloc_list(); - if (!list) - YYNOMEM; - err = parse_events_load_bpf(_parse_state, list, $1, true, $2, &@1); - parse_events_terms__delete($2); - if (err) { - free(list); - PE_ABORT(err); - } - $$ = list; -} - opt_event_config: '/' event_config '/' { -- GitLab From 5e6da6be3082f77be06894a1a94d52a90b4007dc Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 10 Aug 2023 11:48:51 -0700 Subject: [PATCH 1086/3445] perf trace: Migrate BPF augmentation to use a skeleton Previously a BPF event of augmented_raw_syscalls.c could be used to enable augmentation of syscalls by perf trace. As BPF events are no longer supported, switch to using a BPF skeleton which when attached explicitly opens the sysenter and sysexit tracepoints. The dump map is removed as debugging wasn't supported by the augmentation and bpf_printk can be used when necessary. Remove tools/perf/examples/bpf/augmented_raw_syscalls.c so that the rename/migration to a BPF skeleton captures that this was the source. Committer notes: Some minor stylistic changes to help visualizing the diff. Use libbpf_strerror when failing to load the augmented raw syscalls BPF. Use bpf_object__for_each_program(prog, trace.skel->obj) to disable auto attachment for all but the sys_enter, sys_exit tracepoints, to avoid having to add extra lines as we go adding support for more pointer receiving syscalls. Committer testing: # perf trace -e open* --max-events=10 0.000 ( 0.022 ms): systemd-oomd/1151 openat(dfd: CWD, filename: "/proc/meminfo", flags: RDONLY|CLOEXEC) = 11 208.833 ( ): gnome-terminal/3223 openat(dfd: CWD, filename: "/proc/51250/cmdline") ... 249.993 ( 0.024 ms): systemd-oomd/1151 openat(dfd: CWD, filename: "/proc/meminfo", flags: RDONLY|CLOEXEC) = 11 250.118 ( 0.030 ms): systemd-oomd/1151 openat(dfd: CWD, filename: "/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/memory.pressure", flags: RDONLY|CLOEXEC) = 11 250.205 ( 0.016 ms): systemd-oomd/1151 openat(dfd: CWD, filename: "/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/memory.current", flags: RDONLY|CLOEXEC) = 11 250.244 ( 0.014 ms): systemd-oomd/1151 openat(dfd: CWD, filename: "/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/memory.min", flags: RDONLY|CLOEXEC) = 11 250.282 ( 0.014 ms): systemd-oomd/1151 openat(dfd: CWD, filename: "/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/memory.low", flags: RDONLY|CLOEXEC) = 11 250.320 ( 0.014 ms): systemd-oomd/1151 openat(dfd: CWD, filename: "/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/memory.swap.current", flags: RDONLY|CLOEXEC) = 11 250.355 ( 0.014 ms): systemd-oomd/1151 openat(dfd: CWD, filename: "/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/memory.stat", flags: RDONLY|CLOEXEC) = 11 250.717 ( 0.016 ms): systemd-oomd/1151 openat(dfd: CWD, filename: "/sys/fs/cgroup/user.slice/user-1001.slice/user@1001.service/memory.pressure", flags: RDONLY|CLOEXEC) = 11 # # perf trace -e *nanosleep* --max-events=10 ? ( ): SCTP timer/28304 ... [continued]: clock_nanosleep()) = 0 0.007 (10.058 ms): SCTP timer/28304 clock_nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }, rmtp: 0x7f0466b78de0) = 0 10.069 ( ): SCTP timer/28304 clock_nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }, rmtp: 0x7f0466b78de0) ... 10.069 (10.056 ms): SCTP timer/28304 ... [continued]: clock_nanosleep()) = 0 17.059 ( ): podman/3572 nanosleep(rqtp: 0x7fc4f4d75be0) ... 17.059 (10.061 ms): podman/3572 ... [continued]: nanosleep()) = 0 20.131 (10.059 ms): SCTP timer/28304 clock_nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }, rmtp: 0x7f0466b78de0) = 0 30.195 (10.038 ms): SCTP timer/28304 clock_nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }, rmtp: 0x7f0466b78de0) = 0 40.238 (10.057 ms): SCTP timer/28304 clock_nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }, rmtp: 0x7f0466b78de0) = 0 50.301 ( ): SCTP timer/28304 clock_nanosleep(rqtp: { .tv_sec: 0, .tv_nsec: 10000000 }, rmtp: 0x7f0466b78de0) ... # # perf trace -e perf_event* -- perf stat -e instructions,cycles,cache-misses sleep 0.1 0.000 ( 0.011 ms): perf/51331 perf_event_open(attr_uptr: { type: 0 (PERF_TYPE_HARDWARE), size: 136, config: 0x1 (PERF_COUNT_HW_INSTRUCTIONS), sample_type: IDENTIFIER, read_format: TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING, disabled: 1, inherit: 1, enable_on_exec: 1, exclude_guest: 1 }, pid: 51332 (perf), cpu: -1, group_fd: -1, flags: FD_CLOEXEC) = 3 0.013 ( 0.003 ms): perf/51331 perf_event_open(attr_uptr: { type: 0 (PERF_TYPE_HARDWARE), size: 136, config: 0 (PERF_COUNT_HW_CPU_CYCLES), sample_type: IDENTIFIER, read_format: TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING, disabled: 1, inherit: 1, enable_on_exec: 1, exclude_guest: 1 }, pid: 51332 (perf), cpu: -1, group_fd: -1, flags: FD_CLOEXEC) = 4 0.017 ( 0.002 ms): perf/51331 perf_event_open(attr_uptr: { type: 0 (PERF_TYPE_HARDWARE), size: 136, config: 0x3 (PERF_COUNT_HW_CACHE_MISSES), sample_type: IDENTIFIER, read_format: TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING, disabled: 1, inherit: 1, enable_on_exec: 1, exclude_guest: 1 }, pid: 51332 (perf), cpu: -1, group_fd: -1, flags: FD_CLOEXEC) = 5 Performance counter stats for 'sleep 0.1': 1,495,051 instructions # 1.11 insn per cycle 1,347,641 cycles 35,424 cache-misses 0.100935279 seconds time elapsed 0.000924000 seconds user 0.000000000 seconds sys # # perf trace -e connect* ssh localhost 0.000 ( 0.012 ms): ssh/51346 connect(fd: 4, uservaddr: { .family: LOCAL, path: /var/lib/sss/pipes/nss }, addrlen: 110) = -1 ECONNREFUSED (Connection refused) 0.118 ( 0.004 ms): ssh/51346 connect(fd: 6, uservaddr: { .family: LOCAL, path: /var/lib/sss/pipes/nss }, addrlen: 110) = -1 ECONNREFUSED (Connection refused) 0.399 ( 0.007 ms): ssh/51346 connect(fd: 4, uservaddr: { .family: LOCAL, path: /var/lib/sss/pipes/nss }, addrlen: 110) = -1 ECONNREFUSED (Connection refused) 0.426 ( 0.003 ms): ssh/51346 connect(fd: 4, uservaddr: { .family: LOCAL, path: /var/lib/sss/pipes/nss }, addrlen: 110) = -1 ECONNREFUSED (Connection refused) 0.754 ( 0.009 ms): ssh/51346 connect(fd: 4, uservaddr: { .family: INET, port: 22, addr: 127.0.0.1 }, addrlen: 16) = 0 0.771 ( 0.010 ms): ssh/51346 connect(fd: 4, uservaddr: { .family: INET6, port: 22, addr: ::1 }, addrlen: 28) = 0 0.798 ( 0.053 ms): ssh/51346 connect(fd: 4, uservaddr: { .family: INET6, port: 22, addr: ::1 }, addrlen: 28) = 0 0.870 ( 0.004 ms): ssh/51346 connect(fd: 5, uservaddr: { .family: LOCAL, path: /var/lib/sss/pipes/nss }, addrlen: 110) = -1 ECONNREFUSED (Connection refused) 0.904 ( 0.003 ms): ssh/51346 connect(fd: 5, uservaddr: { .family: LOCAL, path: /var/lib/sss/pipes/nss }, addrlen: 110) = -1 ECONNREFUSED (Connection refused) 0.930 ( 0.003 ms): ssh/51346 connect(fd: 5, uservaddr: { .family: LOCAL, path: /var/lib/sss/pipes/nss }, addrlen: 110) = -1 ECONNREFUSED (Connection refused) 0.957 ( 0.003 ms): ssh/51346 connect(fd: 5, uservaddr: { .family: LOCAL, path: /var/lib/sss/pipes/nss }, addrlen: 110) = -1 ECONNREFUSED (Connection refused) 0.981 ( 0.003 ms): ssh/51346 connect(fd: 5, uservaddr: { .family: LOCAL, path: /var/lib/sss/pipes/nss }, addrlen: 110) = -1 ECONNREFUSED (Connection refused) 1.006 ( 0.004 ms): ssh/51346 connect(fd: 5, uservaddr: { .family: LOCAL, path: /var/lib/sss/pipes/nss }, addrlen: 110) = -1 ECONNREFUSED (Connection refused) 1.036 ( 0.005 ms): ssh/51346 connect(fd: 5, uservaddr: { .family: LOCAL, path: /var/lib/sss/pipes/nss }, addrlen: 110) = -1 ECONNREFUSED (Connection refused) 65.077 ( 0.022 ms): ssh/51346 connect(fd: 5, uservaddr: { .family: LOCAL, path: /var/run/.heim_org.h5l.kcm-socket }, addrlen: 110) = 0 66.608 ( 0.014 ms): ssh/51346 connect(fd: 5, uservaddr: { .family: LOCAL, path: /var/run/.heim_org.h5l.kcm-socket }, addrlen: 110) = 0 root@localhost's password: # # perf trace -e sendto* ping -c 2 localhost PING localhost(localhost (::1)) 56 data bytes 64 bytes from localhost (::1): icmp_seq=1 ttl=64 time=0.024 ms 0.000 ( 0.011 ms): ping/51357 sendto(fd: 5, buff: 0x7ffcca35e620, len: 20, addr: { .family: NETLINK }, addr_len: 0xc) = 20 0.135 ( 0.026 ms): ping/51357 sendto(fd: 4, buff: 0x5601398f7b20, len: 64, addr: { .family: INET6, port: 58, addr: ::1 }, addr_len: 0x1c) = 64 1014.929 ( 0.050 ms): ping/51357 sendto(fd: 4, buff: 0x5601398f7b20, len: 64, flags: CONFIRM, addr: { .family: INET6, port: 58, addr: ::1 }, addr_len: 0x1c) = 64 64 bytes from localhost (::1): icmp_seq=2 ttl=64 time=0.046 ms --- localhost ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1015ms rtt min/avg/max/mdev = 0.024/0.035/0.046/0.011 ms # Signed-off-by: Ian Rogers Acked-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Andrii Nakryiko Cc: Anshuman Khandual Cc: Athira Rajeev Cc: Brendan Gregg Cc: Carsten Haitzler Cc: Eduard Zingerman Cc: Fangrui Song Cc: He Kuang Cc: Ingo Molnar Cc: James Clark Cc: Kan Liang Cc: Leo Yan Cc: Madhavan Srinivasan Cc: Mark Rutland Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Naveen N. Rao Cc: Nick Desaulniers Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Rob Herring Cc: Tiezhu Yang Cc: Tom Rix Cc: Wang Nan Cc: Wang ShaoBo Cc: Yang Jihong Cc: Yonghong Song Cc: YueHaibing Cc: bpf@vger.kernel.org Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230810184853.2860737-3-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 1 + tools/perf/builtin-trace.c | 159 +++++++++++------- .../bpf_skel/augmented_raw_syscalls.bpf.c} | 27 +-- 3 files changed, 110 insertions(+), 77 deletions(-) rename tools/perf/{examples/bpf/augmented_raw_syscalls.c => util/bpf_skel/augmented_raw_syscalls.bpf.c} (96%) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 5370d7bf123e7..40663c69b25c6 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -1038,6 +1038,7 @@ SKELETONS += $(SKEL_OUT)/bperf_cgroup.skel.h $(SKEL_OUT)/func_latency.skel.h SKELETONS += $(SKEL_OUT)/off_cpu.skel.h $(SKEL_OUT)/lock_contention.skel.h SKELETONS += $(SKEL_OUT)/kwork_trace.skel.h $(SKEL_OUT)/sample_filter.skel.h SKELETONS += $(SKEL_OUT)/bench_uprobe.skel.h +SKELETONS += $(SKEL_OUT)/augmented_raw_syscalls.skel.h $(SKEL_TMP_OUT) $(LIBAPI_OUTPUT) $(LIBBPF_OUTPUT) $(LIBPERF_OUTPUT) $(LIBSUBCMD_OUTPUT) $(LIBSYMBOL_OUTPUT): $(Q)$(MKDIR) -p $@ diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 59862467e781f..0ebfa95895e0b 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -19,6 +19,9 @@ #ifdef HAVE_LIBBPF_SUPPORT #include #include +#ifdef HAVE_BPF_SKEL +#include "bpf_skel/augmented_raw_syscalls.skel.h" +#endif #endif #include "util/bpf_map.h" #include "util/rlimit.h" @@ -127,25 +130,19 @@ struct trace { struct syscalltbl *sctbl; struct { struct syscall *table; - struct { // per syscall BPF_MAP_TYPE_PROG_ARRAY - struct bpf_map *sys_enter, - *sys_exit; - } prog_array; struct { struct evsel *sys_enter, - *sys_exit, - *augmented; + *sys_exit, + *bpf_output; } events; - struct bpf_program *unaugmented_prog; } syscalls; - struct { - struct bpf_map *map; - } dump; +#ifdef HAVE_BPF_SKEL + struct augmented_raw_syscalls_bpf *skel; +#endif struct record_opts opts; struct evlist *evlist; struct machine *host; struct thread *current; - struct bpf_object *bpf_obj; struct cgroup *cgroup; u64 base_time; FILE *output; @@ -415,6 +412,7 @@ static int evsel__init_syscall_tp(struct evsel *evsel) if (evsel__init_tp_uint_field(evsel, &sc->id, "__syscall_nr") && evsel__init_tp_uint_field(evsel, &sc->id, "nr")) return -ENOENT; + return 0; } @@ -2845,7 +2843,7 @@ static int trace__event_handler(struct trace *trace, struct evsel *evsel, if (thread) trace__fprintf_comm_tid(trace, thread, trace->output); - if (evsel == trace->syscalls.events.augmented) { + if (evsel == trace->syscalls.events.bpf_output) { int id = perf_evsel__sc_tp_uint(evsel, id, sample); struct syscall *sc = trace__syscall_info(trace, evsel, id); @@ -3278,24 +3276,16 @@ out_enomem: goto out; } -#ifdef HAVE_LIBBPF_SUPPORT -static struct bpf_map *trace__find_bpf_map_by_name(struct trace *trace, const char *name) -{ - if (trace->bpf_obj == NULL) - return NULL; - - return bpf_object__find_map_by_name(trace->bpf_obj, name); -} - +#ifdef HAVE_BPF_SKEL static struct bpf_program *trace__find_bpf_program_by_title(struct trace *trace, const char *name) { struct bpf_program *pos, *prog = NULL; const char *sec_name; - if (trace->bpf_obj == NULL) + if (trace->skel->obj == NULL) return NULL; - bpf_object__for_each_program(pos, trace->bpf_obj) { + bpf_object__for_each_program(pos, trace->skel->obj) { sec_name = bpf_program__section_name(pos); if (sec_name && !strcmp(sec_name, name)) { prog = pos; @@ -3313,12 +3303,12 @@ static struct bpf_program *trace__find_syscall_bpf_prog(struct trace *trace, str if (prog_name == NULL) { char default_prog_name[256]; - scnprintf(default_prog_name, sizeof(default_prog_name), "!syscalls:sys_%s_%s", type, sc->name); + scnprintf(default_prog_name, sizeof(default_prog_name), "tp/syscalls/sys_%s_%s", type, sc->name); prog = trace__find_bpf_program_by_title(trace, default_prog_name); if (prog != NULL) goto out_found; if (sc->fmt && sc->fmt->alias) { - scnprintf(default_prog_name, sizeof(default_prog_name), "!syscalls:sys_%s_%s", type, sc->fmt->alias); + scnprintf(default_prog_name, sizeof(default_prog_name), "tp/syscalls/sys_%s_%s", type, sc->fmt->alias); prog = trace__find_bpf_program_by_title(trace, default_prog_name); if (prog != NULL) goto out_found; @@ -3336,7 +3326,7 @@ out_found: pr_debug("Couldn't find BPF prog \"%s\" to associate with syscalls:sys_%s_%s, not augmenting it\n", prog_name, type, sc->name); out_unaugmented: - return trace->syscalls.unaugmented_prog; + return trace->skel->progs.syscall_unaugmented; } static void trace__init_syscall_bpf_progs(struct trace *trace, int id) @@ -3353,13 +3343,13 @@ static void trace__init_syscall_bpf_progs(struct trace *trace, int id) static int trace__bpf_prog_sys_enter_fd(struct trace *trace, int id) { struct syscall *sc = trace__syscall_info(trace, NULL, id); - return sc ? bpf_program__fd(sc->bpf_prog.sys_enter) : bpf_program__fd(trace->syscalls.unaugmented_prog); + return sc ? bpf_program__fd(sc->bpf_prog.sys_enter) : bpf_program__fd(trace->skel->progs.syscall_unaugmented); } static int trace__bpf_prog_sys_exit_fd(struct trace *trace, int id) { struct syscall *sc = trace__syscall_info(trace, NULL, id); - return sc ? bpf_program__fd(sc->bpf_prog.sys_exit) : bpf_program__fd(trace->syscalls.unaugmented_prog); + return sc ? bpf_program__fd(sc->bpf_prog.sys_exit) : bpf_program__fd(trace->skel->progs.syscall_unaugmented); } static struct bpf_program *trace__find_usable_bpf_prog_entry(struct trace *trace, struct syscall *sc) @@ -3384,7 +3374,7 @@ try_to_find_pair: bool is_candidate = false; if (pair == NULL || pair == sc || - pair->bpf_prog.sys_enter == trace->syscalls.unaugmented_prog) + pair->bpf_prog.sys_enter == trace->skel->progs.syscall_unaugmented) continue; for (field = sc->args, candidate_field = pair->args; @@ -3437,7 +3427,7 @@ try_to_find_pair: */ if (pair_prog == NULL) { pair_prog = trace__find_syscall_bpf_prog(trace, pair, pair->fmt ? pair->fmt->bpf_prog_name.sys_enter : NULL, "enter"); - if (pair_prog == trace->syscalls.unaugmented_prog) + if (pair_prog == trace->skel->progs.syscall_unaugmented) goto next_candidate; } @@ -3452,8 +3442,8 @@ try_to_find_pair: static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace) { - int map_enter_fd = bpf_map__fd(trace->syscalls.prog_array.sys_enter), - map_exit_fd = bpf_map__fd(trace->syscalls.prog_array.sys_exit); + int map_enter_fd = bpf_map__fd(trace->skel->maps.syscalls_sys_enter); + int map_exit_fd = bpf_map__fd(trace->skel->maps.syscalls_sys_exit); int err = 0, key; for (key = 0; key < trace->sctbl->syscalls.nr_entries; ++key) { @@ -3515,7 +3505,7 @@ static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace) * For now we're just reusing the sys_enter prog, and if it * already has an augmenter, we don't need to find one. */ - if (sc->bpf_prog.sys_enter != trace->syscalls.unaugmented_prog) + if (sc->bpf_prog.sys_enter != trace->skel->progs.syscall_unaugmented) continue; /* @@ -3538,22 +3528,9 @@ static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace) break; } - return err; } - -#else // HAVE_LIBBPF_SUPPORT -static struct bpf_map *trace__find_bpf_map_by_name(struct trace *trace __maybe_unused, - const char *name __maybe_unused) -{ - return NULL; -} - -static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace __maybe_unused) -{ - return 0; -} -#endif // HAVE_LIBBPF_SUPPORT +#endif // HAVE_BPF_SKEL static int trace__set_ev_qualifier_filter(struct trace *trace) { @@ -3917,13 +3894,31 @@ static int trace__run(struct trace *trace, int argc, const char **argv) err = evlist__open(evlist); if (err < 0) goto out_error_open; +#ifdef HAVE_BPF_SKEL + { + struct perf_cpu cpu; + /* + * Set up the __augmented_syscalls__ BPF map to hold for each + * CPU the bpf-output event's file descriptor. + */ + perf_cpu_map__for_each_cpu(cpu, i, trace->syscalls.events.bpf_output->core.cpus) { + bpf_map__update_elem(trace->skel->maps.__augmented_syscalls__, + &cpu.cpu, sizeof(int), + xyarray__entry(trace->syscalls.events.bpf_output->core.fd, + cpu.cpu, 0), + sizeof(__u32), BPF_ANY); + } + } +#endif err = trace__set_filter_pids(trace); if (err < 0) goto out_error_mem; - if (trace->syscalls.prog_array.sys_enter) +#ifdef HAVE_BPF_SKEL + if (trace->skel->progs.sys_enter) trace__init_syscalls_bpf_prog_array_maps(trace); +#endif if (trace->ev_qualifier_ids.nr > 0) { err = trace__set_ev_qualifier_filter(trace); @@ -3956,9 +3951,6 @@ static int trace__run(struct trace *trace, int argc, const char **argv) if (err < 0) goto out_error_apply_filters; - if (trace->dump.map) - bpf_map__fprintf(trace->dump.map, trace->output); - err = evlist__mmap(evlist, trace->opts.mmap_pages); if (err < 0) goto out_error_mmap; @@ -4655,6 +4647,18 @@ static void trace__exit(struct trace *trace) zfree(&trace->perfconfig_events); } +#ifdef HAVE_BPF_SKEL +static int bpf__setup_bpf_output(struct evlist *evlist) +{ + int err = parse_event(evlist, "bpf-output/no-inherit=1,name=__augmented_syscalls__/"); + + if (err) + pr_debug("ERROR: failed to create the \"__augmented_syscalls__\" bpf-output event\n"); + + return err; +} +#endif + int cmd_trace(int argc, const char **argv) { const char *trace_usage[] = { @@ -4686,7 +4690,6 @@ int cmd_trace(int argc, const char **argv) .max_stack = UINT_MAX, .max_events = ULONG_MAX, }; - const char *map_dump_str = NULL; const char *output_name = NULL; const struct option trace_options[] = { OPT_CALLBACK('e', "event", &trace, "event", @@ -4720,9 +4723,6 @@ int cmd_trace(int argc, const char **argv) OPT_CALLBACK(0, "duration", &trace, "float", "show only events with duration > N.M ms", trace__set_duration), -#ifdef HAVE_LIBBPF_SUPPORT - OPT_STRING(0, "map-dump", &map_dump_str, "BPF map", "BPF map to periodically dump"), -#endif OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"), OPT_INCR('v', "verbose", &verbose, "be more verbose"), OPT_BOOLEAN('T', "time", &trace.full_time, @@ -4849,16 +4849,44 @@ int cmd_trace(int argc, const char **argv) "cgroup monitoring only available in system-wide mode"); } - err = -1; +#ifdef HAVE_BPF_SKEL + trace.skel = augmented_raw_syscalls_bpf__open(); + if (!trace.skel) { + pr_debug("Failed to open augmented syscalls BPF skeleton"); + } else { + /* + * Disable attaching the BPF programs except for sys_enter and + * sys_exit that tail call into this as necessary. + */ + struct bpf_program *prog; - if (map_dump_str) { - trace.dump.map = trace__find_bpf_map_by_name(&trace, map_dump_str); - if (trace.dump.map == NULL) { - pr_err("ERROR: BPF map \"%s\" not found\n", map_dump_str); - goto out; + bpf_object__for_each_program(prog, trace.skel->obj) { + if (prog != trace.skel->progs.sys_enter && prog != trace.skel->progs.sys_exit) + bpf_program__set_autoattach(prog, /*autoattach=*/false); + } + + err = augmented_raw_syscalls_bpf__load(trace.skel); + + if (err < 0) { + libbpf_strerror(err, bf, sizeof(bf)); + pr_debug("Failed to load augmented syscalls BPF skeleton: %s\n", bf); + } else { + augmented_raw_syscalls_bpf__attach(trace.skel); + trace__add_syscall_newtp(&trace); } } + err = bpf__setup_bpf_output(trace.evlist); + if (err) { + libbpf_strerror(err, bf, sizeof(bf)); + pr_err("ERROR: Setup BPF output event failed: %s\n", bf); + goto out; + } + trace.syscalls.events.bpf_output = evlist__last(trace.evlist); + assert(!strcmp(evsel__name(trace.syscalls.events.bpf_output), "__augmented_syscalls__")); +#endif + err = -1; + if (trace.trace_pgfaults) { trace.opts.sample_address = true; trace.opts.sample_time = true; @@ -4909,7 +4937,7 @@ int cmd_trace(int argc, const char **argv) * buffers that are being copied from kernel to userspace, think 'read' * syscall. */ - if (trace.syscalls.events.augmented) { + if (trace.syscalls.events.bpf_output) { evlist__for_each_entry(trace.evlist, evsel) { bool raw_syscalls_sys_exit = strcmp(evsel__name(evsel), "raw_syscalls:sys_exit") == 0; @@ -4918,9 +4946,9 @@ int cmd_trace(int argc, const char **argv) goto init_augmented_syscall_tp; } - if (trace.syscalls.events.augmented->priv == NULL && + if (trace.syscalls.events.bpf_output->priv == NULL && strstr(evsel__name(evsel), "syscalls:sys_enter")) { - struct evsel *augmented = trace.syscalls.events.augmented; + struct evsel *augmented = trace.syscalls.events.bpf_output; if (evsel__init_augmented_syscall_tp(augmented, evsel) || evsel__init_augmented_syscall_tp_args(augmented)) goto out; @@ -5025,5 +5053,8 @@ out_close: fclose(trace.output); out: trace__exit(&trace); +#ifdef HAVE_BPF_SKEL + augmented_raw_syscalls_bpf__destroy(trace.skel); +#endif return err; } diff --git a/tools/perf/examples/bpf/augmented_raw_syscalls.c b/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c similarity index 96% rename from tools/perf/examples/bpf/augmented_raw_syscalls.c rename to tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c index 9a03189d33d38..70478b9460eea 100644 --- a/tools/perf/examples/bpf/augmented_raw_syscalls.c +++ b/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c @@ -18,6 +18,8 @@ #include #include +#define MAX_CPUS 4096 + // FIXME: These should come from system headers typedef char bool; typedef int pid_t; @@ -34,7 +36,7 @@ struct __augmented_syscalls__ { __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); __type(key, int); __type(value, __u32); - __uint(max_entries, __NR_CPUS__); + __uint(max_entries, MAX_CPUS); } __augmented_syscalls__ SEC(".maps"); /* @@ -170,7 +172,7 @@ unsigned int augmented_arg__read_str(struct augmented_arg *augmented_arg, const return augmented_len; } -SEC("!raw_syscalls:unaugmented") +SEC("tp/raw_syscalls/sys_enter") int syscall_unaugmented(struct syscall_enter_args *args) { return 1; @@ -182,7 +184,7 @@ int syscall_unaugmented(struct syscall_enter_args *args) * on from there, reading the first syscall arg as a string, i.e. open's * filename. */ -SEC("!syscalls:sys_enter_connect") +SEC("tp/syscalls/sys_enter_connect") int sys_enter_connect(struct syscall_enter_args *args) { struct augmented_args_payload *augmented_args = augmented_args_payload(); @@ -201,7 +203,7 @@ int sys_enter_connect(struct syscall_enter_args *args) return augmented__output(args, augmented_args, len + socklen); } -SEC("!syscalls:sys_enter_sendto") +SEC("tp/syscalls/sys_enter_sendto") int sys_enter_sendto(struct syscall_enter_args *args) { struct augmented_args_payload *augmented_args = augmented_args_payload(); @@ -220,7 +222,7 @@ int sys_enter_sendto(struct syscall_enter_args *args) return augmented__output(args, augmented_args, len + socklen); } -SEC("!syscalls:sys_enter_open") +SEC("tp/syscalls/sys_enter_open") int sys_enter_open(struct syscall_enter_args *args) { struct augmented_args_payload *augmented_args = augmented_args_payload(); @@ -235,7 +237,7 @@ int sys_enter_open(struct syscall_enter_args *args) return augmented__output(args, augmented_args, len); } -SEC("!syscalls:sys_enter_openat") +SEC("tp/syscalls/sys_enter_openat") int sys_enter_openat(struct syscall_enter_args *args) { struct augmented_args_payload *augmented_args = augmented_args_payload(); @@ -250,7 +252,7 @@ int sys_enter_openat(struct syscall_enter_args *args) return augmented__output(args, augmented_args, len); } -SEC("!syscalls:sys_enter_rename") +SEC("tp/syscalls/sys_enter_rename") int sys_enter_rename(struct syscall_enter_args *args) { struct augmented_args_payload *augmented_args = augmented_args_payload(); @@ -267,7 +269,7 @@ int sys_enter_rename(struct syscall_enter_args *args) return augmented__output(args, augmented_args, len); } -SEC("!syscalls:sys_enter_renameat") +SEC("tp/syscalls/sys_enter_renameat") int sys_enter_renameat(struct syscall_enter_args *args) { struct augmented_args_payload *augmented_args = augmented_args_payload(); @@ -295,7 +297,7 @@ struct perf_event_attr_size { __u32 size; }; -SEC("!syscalls:sys_enter_perf_event_open") +SEC("tp/syscalls/sys_enter_perf_event_open") int sys_enter_perf_event_open(struct syscall_enter_args *args) { struct augmented_args_payload *augmented_args = augmented_args_payload(); @@ -327,7 +329,7 @@ failure: return 1; /* Failure: don't filter */ } -SEC("!syscalls:sys_enter_clock_nanosleep") +SEC("tp/syscalls/sys_enter_clock_nanosleep") int sys_enter_clock_nanosleep(struct syscall_enter_args *args) { struct augmented_args_payload *augmented_args = augmented_args_payload(); @@ -358,7 +360,7 @@ static bool pid_filter__has(struct pids_filtered *pids, pid_t pid) return bpf_map_lookup_elem(pids, &pid) != NULL; } -SEC("raw_syscalls:sys_enter") +SEC("tp/raw_syscalls/sys_enter") int sys_enter(struct syscall_enter_args *args) { struct augmented_args_payload *augmented_args; @@ -371,7 +373,6 @@ int sys_enter(struct syscall_enter_args *args) * We'll add to this as we add augmented syscalls right after that * initial, non-augmented raw_syscalls:sys_enter payload. */ - unsigned int len = sizeof(augmented_args->args); if (pid_filter__has(&pids_filtered, getpid())) return 0; @@ -393,7 +394,7 @@ int sys_enter(struct syscall_enter_args *args) return 0; } -SEC("raw_syscalls:sys_exit") +SEC("tp/raw_syscalls/sys_exit") int sys_exit(struct syscall_exit_args *args) { struct syscall_exit_args exit_args; -- GitLab From 5056c99e8d97e1129ff29826971eefbe345b6837 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 10 Aug 2023 11:48:52 -0700 Subject: [PATCH 1087/3445] perf bpf examples: With no BPF events remove examples The examples were used to give demonstrations of BPF events but such functionality is now subsumed by using --filter with 'perf record' or the direct use of BPF skeletons. Signed-off-by: Ian Rogers Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Andrii Nakryiko Cc: Anshuman Khandual Cc: Athira Rajeev Cc: Brendan Gregg Cc: Carsten Haitzler Cc: Eduard Zingerman Cc: Fangrui Song Cc: He Kuang Cc: Ingo Molnar Cc: James Clark Cc: Kan Liang Cc: Leo Yan Cc: Madhavan Srinivasan Cc: Mark Rutland Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Naveen N. Rao Cc: Nick Desaulniers Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Rob Herring Cc: Tiezhu Yang Cc: Tom Rix Cc: Wang Nan Cc: Wang ShaoBo Cc: Yang Jihong Cc: Yonghong Song Cc: YueHaibing Cc: bpf@vger.kernel.org Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230810184853.2860737-4-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 5 -- tools/perf/examples/bpf/5sec.c | 53 ---------------------- tools/perf/examples/bpf/empty.c | 12 ----- tools/perf/examples/bpf/hello.c | 27 ----------- tools/perf/examples/bpf/sys_enter_openat.c | 33 -------------- 5 files changed, 130 deletions(-) delete mode 100644 tools/perf/examples/bpf/5sec.c delete mode 100644 tools/perf/examples/bpf/empty.c delete mode 100644 tools/perf/examples/bpf/hello.c delete mode 100644 tools/perf/examples/bpf/sys_enter_openat.c diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 40663c69b25c6..c90d55786a028 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -958,11 +958,6 @@ ifndef NO_JVMTI endif $(call QUIET_INSTALL, libexec) \ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' -ifndef NO_LIBBPF - $(call QUIET_INSTALL, bpf-examples) \ - $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_examples_instdir_SQ)/bpf'; \ - $(INSTALL) examples/bpf/*.c -m 644 -t '$(DESTDIR_SQ)$(perf_examples_instdir_SQ)/bpf' -endif $(call QUIET_INSTALL, perf-archive) \ $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' $(call QUIET_INSTALL, perf-iostat) \ diff --git a/tools/perf/examples/bpf/5sec.c b/tools/perf/examples/bpf/5sec.c deleted file mode 100644 index 3bd7fc17631f0..0000000000000 --- a/tools/perf/examples/bpf/5sec.c +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - Description: - - . Disable strace like syscall tracing (--no-syscalls), or try tracing - just some (-e *sleep). - - . Attach a filter function to a kernel function, returning when it should - be considered, i.e. appear on the output. - - . Run it system wide, so that any sleep of >= 5 seconds and < than 6 - seconds gets caught. - - . Ask for callgraphs using DWARF info, so that userspace can be unwound - - . While this is running, run something like "sleep 5s". - - . If we decide to add tv_nsec as well, then it becomes: - - int probe(hrtimer_nanosleep, rqtp->tv_sec rqtp->tv_nsec)(void *ctx, int err, long sec, long nsec) - - I.e. add where it comes from (rqtp->tv_nsec) and where it will be - accessible in the function body (nsec) - - # perf trace --no-syscalls -e tools/perf/examples/bpf/5sec.c/call-graph=dwarf/ - 0.000 perf_bpf_probe:func:(ffffffff9811b5f0) tv_sec=5 - hrtimer_nanosleep ([kernel.kallsyms]) - __x64_sys_nanosleep ([kernel.kallsyms]) - do_syscall_64 ([kernel.kallsyms]) - entry_SYSCALL_64 ([kernel.kallsyms]) - __GI___nanosleep (/usr/lib64/libc-2.26.so) - rpl_nanosleep (/usr/bin/sleep) - xnanosleep (/usr/bin/sleep) - main (/usr/bin/sleep) - __libc_start_main (/usr/lib64/libc-2.26.so) - _start (/usr/bin/sleep) - ^C# - - Copyright (C) 2018 Red Hat, Inc., Arnaldo Carvalho de Melo -*/ - -#include -#include - -#define NSEC_PER_SEC 1000000000L - -SEC("hrtimer_nanosleep=hrtimer_nanosleep rqtp") -int hrtimer_nanosleep(void *ctx, int err, long long sec) -{ - return sec / NSEC_PER_SEC == 5ULL; -} - -char _license[] SEC("license") = "GPL"; diff --git a/tools/perf/examples/bpf/empty.c b/tools/perf/examples/bpf/empty.c deleted file mode 100644 index 3e296c0c53d7d..0000000000000 --- a/tools/perf/examples/bpf/empty.c +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - -struct syscall_enter_args; - -SEC("raw_syscalls:sys_enter") -int sys_enter(struct syscall_enter_args *args) -{ - return 0; -} -char _license[] SEC("license") = "GPL"; diff --git a/tools/perf/examples/bpf/hello.c b/tools/perf/examples/bpf/hello.c deleted file mode 100644 index e9080b0df1587..0000000000000 --- a/tools/perf/examples/bpf/hello.c +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - -struct __bpf_stdout__ { - __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); - __type(key, int); - __type(value, __u32); - __uint(max_entries, __NR_CPUS__); -} __bpf_stdout__ SEC(".maps"); - -#define puts(from) \ - ({ const int __len = sizeof(from); \ - char __from[sizeof(from)] = from; \ - bpf_perf_event_output(args, &__bpf_stdout__, BPF_F_CURRENT_CPU, \ - &__from, __len & (sizeof(from) - 1)); }) - -struct syscall_enter_args; - -SEC("raw_syscalls:sys_enter") -int sys_enter(struct syscall_enter_args *args) -{ - puts("Hello, world\n"); - return 0; -} - -char _license[] SEC("license") = "GPL"; diff --git a/tools/perf/examples/bpf/sys_enter_openat.c b/tools/perf/examples/bpf/sys_enter_openat.c deleted file mode 100644 index c4481c390d232..0000000000000 --- a/tools/perf/examples/bpf/sys_enter_openat.c +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Hook into 'openat' syscall entry tracepoint - * - * Test it with: - * - * perf trace -e tools/perf/examples/bpf/sys_enter_openat.c cat /etc/passwd > /dev/null - * - * It'll catch some openat syscalls related to the dynamic linked and - * the last one should be the one for '/etc/passwd'. - * - * The syscall_enter_openat_args can be used to get the syscall fields - * and use them for filtering calls, i.e. use in expressions for - * the return value. - */ - -#include - -struct syscall_enter_openat_args { - unsigned long long unused; - long syscall_nr; - long dfd; - char *filename_ptr; - long flags; - long mode; -}; - -int syscall_enter(openat)(struct syscall_enter_openat_args *args) -{ - return 1; -} - -license(GPL); -- GitLab From cd2cece61ac5f900c43df366c9a64ddb62173707 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 10 Aug 2023 11:48:53 -0700 Subject: [PATCH 1088/3445] perf trace: Tidy comments related to BPF + syscall augmentation Now tools/perf/examples/bpf/augmented_syscalls.c is tools/perf/util/bpf_skel/augmented_syscalls.bpf.c and not enabled as a BPF event, tidy the comments to reflect this. Signed-off-by: Ian Rogers Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Andrii Nakryiko Cc: Anshuman Khandual Cc: Athira Rajeev Cc: Brendan Gregg Cc: Carsten Haitzler Cc: Eduard Zingerman Cc: Fangrui Song Cc: He Kuang Cc: Ingo Molnar Cc: James Clark Cc: Kan Liang Cc: Leo Yan Cc: Madhavan Srinivasan Cc: Mark Rutland Cc: Namhyung Kim Cc: Nathan Chancellor Cc: Naveen N. Rao Cc: Nick Desaulniers Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Rob Herring Cc: Tiezhu Yang Cc: Tom Rix Cc: Wang Nan Cc: Wang ShaoBo Cc: Yang Jihong Cc: Yonghong Song Cc: YueHaibing Cc: bpf@vger.kernel.org Cc: llvm@lists.linux.dev Link: https://lore.kernel.org/r/20230810184853.2860737-5-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/trace/beauty/beauty.h | 15 +++++++-------- .../util/bpf_skel/augmented_raw_syscalls.bpf.c | 8 -------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/tools/perf/trace/beauty/beauty.h b/tools/perf/trace/beauty/beauty.h index 3d12bf0f6d072..788e8f6bd90eb 100644 --- a/tools/perf/trace/beauty/beauty.h +++ b/tools/perf/trace/beauty/beauty.h @@ -67,15 +67,14 @@ extern struct strarray strarray__socket_level; /** * augmented_arg: extra payload for syscall pointer arguments - * If perf_sample->raw_size is more than what a syscall sys_enter_FOO puts, - * then its the arguments contents, so that we can show more than just a + * If perf_sample->raw_size is more than what a syscall sys_enter_FOO puts, then + * its the arguments contents, so that we can show more than just a * pointer. This will be done initially with eBPF, the start of that is at the - * tools/perf/examples/bpf/augmented_syscalls.c example for the openat, but - * will eventually be done automagically caching the running kernel tracefs - * events data into an eBPF C script, that then gets compiled and its .o file - * cached for subsequent use. For char pointers like the ones for 'open' like - * syscalls its easy, for the rest we should use DWARF or better, BTF, much - * more compact. + * tools/perf/util/bpf_skel/augmented_syscalls.bpf.c that will eventually be + * done automagically caching the running kernel tracefs events data into an + * eBPF C script, that then gets compiled and its .o file cached for subsequent + * use. For char pointers like the ones for 'open' like syscalls its easy, for + * the rest we should use DWARF or better, BTF, much more compact. * * @size: 8 if all we need is an integer, otherwise all of the augmented arg. * @int_arg: will be used for integer like pointer contents, like 'accept's 'upeer_addrlen' diff --git a/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c b/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c index 70478b9460eea..0586c4118656d 100644 --- a/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c +++ b/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c @@ -2,16 +2,8 @@ /* * Augment the raw_syscalls tracepoints with the contents of the pointer arguments. * - * Test it with: - * - * perf trace -e tools/perf/examples/bpf/augmented_raw_syscalls.c cat /etc/passwd > /dev/null - * * This exactly matches what is marshalled into the raw_syscall:sys_enter * payload expected by the 'perf trace' beautifiers. - * - * For now it just uses the existing tracepoint augmentation code in 'perf - * trace', in the next csets we'll hook up these with the sys_enter/sys_exit - * code that will combine entry/exit in a strace like way. */ #include -- GitLab From dc7f01f1bceca38839992b3371e0be8a3c9d5acf Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 10 Aug 2023 19:58:21 -0700 Subject: [PATCH 1089/3445] perf bpf-filter: Fix sample flag check with || For logical OR operator, the actual sample_flags are in the 'groups' list so it needs to check entries in the list instead. Otherwise it would show the following error message. $ sudo perf record -a -e cycles:p --filter 'period > 100 || weight > 0' sleep 1 Error: cycles:p event does not have sample flags 0 failed to set filter "BPF" on event cycles:p with 2 (No such file or directory) Actually it should warn on 'weight' is used without WEIGHT flag. Error: cycles:p event does not have PERF_SAMPLE_WEIGHT Hint: please add -W option to perf record failed to set filter "BPF" on event cycles:p with 2 (No such file or directory) Fixes: 4310551b76e0d676 ("perf bpf filter: Show warning for missing sample flags") Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20230811025822.3859771-1-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/bpf-filter.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/perf/util/bpf-filter.c b/tools/perf/util/bpf-filter.c index 47f01df658d9a..b51544996046d 100644 --- a/tools/perf/util/bpf-filter.c +++ b/tools/perf/util/bpf-filter.c @@ -62,6 +62,16 @@ static int check_sample_flags(struct evsel *evsel, struct perf_bpf_filter_expr * if (evsel->core.attr.sample_type & expr->sample_flags) return 0; + if (expr->op == PBF_OP_GROUP_BEGIN) { + struct perf_bpf_filter_expr *group; + + list_for_each_entry(group, &expr->groups, list) { + if (check_sample_flags(evsel, group) < 0) + return -1; + } + return 0; + } + info = get_sample_info(expr->sample_flags); if (info == NULL) { pr_err("Error: %s event does not have sample flags %lx\n", -- GitLab From 9575ecdd198a50e95ed2319471f7518465b1cd94 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 10 Aug 2023 19:58:22 -0700 Subject: [PATCH 1090/3445] perf test: Add perf record sample filtering test $ sudo ./perf test 'sample filter' -v 94: perf record sample filtering (by BPF) tests : --- start --- test child forked, pid 3817527 Checking BPF-filter privilege Basic bpf-filter test Basic bpf-filter test [Success] Failing bpf-filter test Error: task-clock event does not have PERF_SAMPLE_CPU Failing bpf-filter test [Success] Group bpf-filter test Error: task-clock event does not have PERF_SAMPLE_CPU Error: task-clock event does not have PERF_SAMPLE_CODE_PAGE_SIZE Group bpf-filter test [Success] test child finished with 0 ---- end ---- perf record sample filtering (by BPF) tests: Ok Reviewed-by: Ian Rogers Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Athira Rajeev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20230811025822.3859771-2-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/record_bpf_filter.sh | 128 ++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100755 tools/perf/tests/shell/record_bpf_filter.sh diff --git a/tools/perf/tests/shell/record_bpf_filter.sh b/tools/perf/tests/shell/record_bpf_filter.sh new file mode 100755 index 0000000000000..e76ea861b92cd --- /dev/null +++ b/tools/perf/tests/shell/record_bpf_filter.sh @@ -0,0 +1,128 @@ +#!/bin/sh +# perf record sample filtering (by BPF) tests +# SPDX-License-Identifier: GPL-2.0 + +set -e + +err=0 +perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) + +cleanup() { + rm -f "${perfdata}" + rm -f "${perfdata}".old + trap - EXIT TERM INT +} + +trap_cleanup() { + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + +test_bpf_filter_priv() { + echo "Checking BPF-filter privilege" + + if [ "$(id -u)" != 0 ] + then + echo "bpf-filter test [Skipped permission]" + err=2 + return + fi + if ! perf record -e task-clock --filter 'period > 1' \ + -o /dev/null --quiet true 2>&1 + then + echo "bpf-filter test [Skipped missing BPF support]" + err=2 + return + fi +} + +test_bpf_filter_basic() { + echo "Basic bpf-filter test" + + if ! perf record -e task-clock -c 10000 --filter 'ip < 0xffffffff00000000' \ + -o "${perfdata}" true 2> /dev/null + then + echo "Basic bpf-filter test [Failed record]" + err=1 + return + fi + if perf script -i "${perfdata}" -F ip | grep 'ffffffff[0-9a-f]*' + then + echo "Basic bpf-filter test [Failed invalid output]" + err=1 + return + fi + echo "Basic bpf-filter test [Success]" +} + +test_bpf_filter_fail() { + echo "Failing bpf-filter test" + + # 'cpu' requires PERF_SAMPLE_CPU flag + if ! perf record -e task-clock --filter 'cpu > 0' \ + -o /dev/null true 2>&1 | grep PERF_SAMPLE_CPU + then + echo "Failing bpf-filter test [Failed forbidden CPU]" + err=1 + return + fi + + if ! perf record --sample-cpu -e task-clock --filter 'cpu > 0' \ + -o /dev/null true 2>/dev/null + then + echo "Failing bpf-filter test [Failed should succeed]" + err=1 + return + fi + + echo "Failing bpf-filter test [Success]" +} + +test_bpf_filter_group() { + echo "Group bpf-filter test" + + if ! perf record -e task-clock --filter 'period > 1000 || ip > 0' \ + -o /dev/null true 2>/dev/null + then + echo "Group bpf-filter test [Failed should succeed]" + err=1 + return + fi + + if ! perf record -e task-clock --filter 'cpu > 0 || ip > 0' \ + -o /dev/null true 2>&1 | grep PERF_SAMPLE_CPU + then + echo "Group bpf-filter test [Failed forbidden CPU]" + err=1 + return + fi + + if ! perf record -e task-clock --filter 'period > 0 || code_pgsz > 4096' \ + -o /dev/null true 2>&1 | grep PERF_SAMPLE_CODE_PAGE_SIZE + then + echo "Group bpf-filter test [Failed forbidden CODE_PAGE_SIZE]" + err=1 + return + fi + + echo "Group bpf-filter test [Success]" +} + + +test_bpf_filter_priv + +if [ $err = 0 ]; then + test_bpf_filter_basic +fi + +if [ $err = 0 ]; then + test_bpf_filter_fail +fi + +if [ $err = 0 ]; then + test_bpf_filter_group +fi + +cleanup +exit $err -- GitLab From d095ad45e2d808a5c8c047b5c8d5e0fad7fec4e4 Mon Sep 17 00:00:00 2001 From: Yang Jihong Date: Tue, 15 Aug 2023 22:10:09 +0000 Subject: [PATCH 1091/3445] perf evsel: Remove duplicate check for `field` in evsel__intval() The `file` parameter in evsel__intval() is checked repeatedly, fix it. No functional change. Signed-off-by: Yang Jihong Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Sandipan Das Link: https://lore.kernel.org/r/20230815221009.3641751-1-yangjihong1@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index e41bc4d9925f6..0c50c443d4560 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -2827,9 +2827,6 @@ u64 evsel__intval(struct evsel *evsel, struct perf_sample *sample, const char *n { struct tep_format_field *field = evsel__field(evsel, name); - if (!field) - return 0; - return field ? format_field__intval(field, sample, evsel->needs_swap) : 0; } #endif -- GitLab From 708a3e8b80a5364fc3dd4991f1e589a6d7a4a8e0 Mon Sep 17 00:00:00 2001 From: Wei Li Date: Tue, 15 Aug 2023 21:17:35 +0800 Subject: [PATCH 1092/3445] perf scripts python: Support syscall name parsing on arm64 In the result of "perf script syscall-counts" on arm64, the syscall events are not resolved currently. Add "aarch64" to audit uname list to support name parsing. * After the patch: [root@localhost ~]# perf script syscall-counts sleep 1 Press control+C to stop and show the summary syscall events: event count ---------------------------------------- ----------- mmap 6 close 5 mprotect 4 brk 3 newfstatat 3 openat 3 getrandom 1 prlimit64 1 munmap 1 clock_nanosleep 1 set_robust_list 1 set_tid_address 1 exit_group 1 read 1 faccessat 1 Signed-off-by: Wei Li Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Li Bin Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20230815131735.1237221-1-liwei391@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py index 7384dcb628c43..c37a03fb7ec53 100644 --- a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py +++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py @@ -54,6 +54,7 @@ try: import audit machine_to_id = { 'x86_64': audit.MACH_86_64, + 'aarch64': audit.MACH_AARCH64, 'alpha' : audit.MACH_ALPHA, 'ia64' : audit.MACH_IA64, 'ppc' : audit.MACH_PPC, -- GitLab From 41a37430f66560c4b9a9d68a977c8dab65b97ff8 Mon Sep 17 00:00:00 2001 From: Wei Li Date: Tue, 15 Aug 2023 21:18:05 +0800 Subject: [PATCH 1093/3445] perf scripts python: Update audit-libs package name for python3 'audit-libs-python' is the package for python2, update it for python3. On Ubuntu and Fedora, the new package is 'python3-audit'. Signed-off-by: Wei Li Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Li Bin Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20230815131805.1237491-1-liwei391@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- .../scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py index c37a03fb7ec53..b75d31858e545 100644 --- a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py +++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py @@ -74,9 +74,9 @@ try: except: if not audit_package_warned: audit_package_warned = True - print("Install the audit-libs-python package to get syscall names.\n" - "For example:\n # apt-get install python-audit (Ubuntu)" - "\n # yum install audit-libs-python (Fedora)" + print("Install the python-audit package to get syscall names.\n" + "For example:\n # apt-get install python3-audit (Ubuntu)" + "\n # yum install python3-audit (Fedora)" "\n etc.\n") def syscall_name(id): -- GitLab From f178a76b054fd046d212c3c67745146ff191a443 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 31 Jul 2023 12:18:55 +0300 Subject: [PATCH 1094/3445] perf dlfilter: Add a test for resolve_address() Extend the "dlfilter C API" test to test perf_dlfilter_fns.resolve_address(). The test currently fails, but passes after a subsequent patch. Reviewed-by: Ian Rogers Signed-off-by: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/r/20230731091857.10681-1-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/dlfilters/dlfilter-test-api-v0.c | 26 ++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tools/perf/dlfilters/dlfilter-test-api-v0.c b/tools/perf/dlfilters/dlfilter-test-api-v0.c index b1f51efd67d63..72f263d491211 100644 --- a/tools/perf/dlfilters/dlfilter-test-api-v0.c +++ b/tools/perf/dlfilters/dlfilter-test-api-v0.c @@ -254,6 +254,30 @@ static int check_addr_al(void *ctx) return 0; } +static int check_address_al(void *ctx, const struct perf_dlfilter_sample *sample) +{ + struct perf_dlfilter_al address_al; + const struct perf_dlfilter_al *al; + + al = perf_dlfilter_fns.resolve_ip(ctx); + if (!al) + return test_fail("resolve_ip() failed"); + + address_al.size = sizeof(address_al); + if (perf_dlfilter_fns.resolve_address(ctx, sample->ip, &address_al)) + return test_fail("resolve_address() failed"); + + CHECK(address_al.sym && al->sym); + CHECK(!strcmp(address_al.sym, al->sym)); + CHECK(address_al.addr == al->addr); + CHECK(address_al.sym_start == al->sym_start); + CHECK(address_al.sym_end == al->sym_end); + CHECK(address_al.dso && al->dso); + CHECK(!strcmp(address_al.dso, al->dso)); + + return 0; +} + static int check_attr(void *ctx) { struct perf_event_attr *attr = perf_dlfilter_fns.attr(ctx); @@ -290,7 +314,7 @@ static int do_checks(void *data, const struct perf_dlfilter_sample *sample, void if (early && !d->do_early) return 0; - if (check_al(ctx) || check_addr_al(ctx)) + if (check_al(ctx) || check_addr_al(ctx) || check_address_al(ctx, sample)) return -1; if (early) -- GitLab From 42c6dd9d23019ff339d0aca80a444eb71087050e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 31 Jul 2023 12:18:56 +0300 Subject: [PATCH 1095/3445] perf dlfilter: Initialize addr_location before passing it to thread__find_symbol_fb() As thread__find_symbol_fb() will end up calling thread__find_map() and it in turn will call these on uninitialized memory: maps__zput(al->maps); map__zput(al->map); thread__zput(al->thread); Fixes: 0dd5041c9a0eaf8c ("perf addr_location: Add init/exit/copy functions") Reviewed-by: Ian Rogers Cc: Adrian Hunter Cc: Aneesh Kumar K.V Cc: Athira Rajeev Cc: Disha Goel Cc: Jiri Olsa Cc: Kajol Jain Cc: Madhavan Srinivasan Cc: Namhyung Kim Link: https://lore.kernel.org/r/20230731091857.10681-2-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dlfilter.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/dlfilter.c b/tools/perf/util/dlfilter.c index 46f74b2344dbb..798a53d7e6c9d 100644 --- a/tools/perf/util/dlfilter.c +++ b/tools/perf/util/dlfilter.c @@ -166,6 +166,7 @@ static __s32 dlfilter__resolve_address(void *ctx, __u64 address, struct perf_dlf if (!thread) return -1; + addr_location__init(&al); thread__find_symbol_fb(thread, d->sample->cpumode, address, &al); al_to_d_al(&al, &d_al); -- GitLab From 82b0a10390e5f198a4e23c9cc6a7307d2cf099f3 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 31 Jul 2023 12:18:57 +0300 Subject: [PATCH 1096/3445] perf dlfilter: Add al_cleanup() Add perf_dlfilter_fns.al_cleanup() to do addr_location__exit() on data passed via perf_dlfilter_fns.resolve_address(). Add dlfilter-test-api-v2 to the "dlfilter C API" test to test it. Update documentation, clarifying that data returned by APIs should not be dereferenced after filter_event() and filter_event_early() return. Fixes: 0dd5041c9a0eaf8c ("perf addr_location: Add init/exit/copy functions") Reviewed-by: Ian Rogers Signed-off-by: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lore.kernel.org/r/20230731091857.10681-3-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-dlfilter.txt | 22 +- tools/perf/Makefile.perf | 2 +- tools/perf/dlfilters/dlfilter-test-api-v2.c | 377 ++++++++++++++++++++ tools/perf/include/perf/perf_dlfilter.h | 11 +- tools/perf/tests/dlfilter-test.c | 38 +- tools/perf/util/dlfilter.c | 29 ++ 6 files changed, 464 insertions(+), 15 deletions(-) create mode 100644 tools/perf/dlfilters/dlfilter-test-api-v2.c diff --git a/tools/perf/Documentation/perf-dlfilter.txt b/tools/perf/Documentation/perf-dlfilter.txt index fb22e3b31dc5c..8887cc20a809e 100644 --- a/tools/perf/Documentation/perf-dlfilter.txt +++ b/tools/perf/Documentation/perf-dlfilter.txt @@ -64,6 +64,12 @@ internal filtering. If implemented, 'filter_description' should return a one-line description of the filter, and optionally a longer description. +Do not assume the 'sample' argument is valid (dereferenceable) +after 'filter_event' and 'filter_event_early' return. + +Do not assume data referenced by pointers in struct perf_dlfilter_sample +is valid (dereferenceable) after 'filter_event' and 'filter_event_early' return. + The perf_dlfilter_sample structure ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -150,7 +156,8 @@ struct perf_dlfilter_fns { const char *(*srcline)(void *ctx, __u32 *line_number); struct perf_event_attr *(*attr)(void *ctx); __s32 (*object_code)(void *ctx, __u64 ip, void *buf, __u32 len); - void *(*reserved[120])(void *); + void (*al_cleanup)(void *ctx, struct perf_dlfilter_al *al); + void *(*reserved[119])(void *); }; ---- @@ -161,7 +168,8 @@ struct perf_dlfilter_fns { 'args' returns arguments from --dlarg options. 'resolve_address' provides information about 'address'. al->size must be set -before calling. Returns 0 on success, -1 otherwise. +before calling. Returns 0 on success, -1 otherwise. Call al_cleanup() (if present, +see below) when 'al' data is no longer needed. 'insn' returns instruction bytes and length. @@ -171,6 +179,12 @@ before calling. Returns 0 on success, -1 otherwise. 'object_code' reads object code and returns the number of bytes read. +'al_cleanup' must be called (if present, so check perf_dlfilter_fns.al_cleanup != NULL) +after resolve_address() to free any associated resources. + +Do not assume pointers obtained via perf_dlfilter_fns are valid (dereferenceable) +after 'filter_event' and 'filter_event_early' return. + The perf_dlfilter_al structure ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -197,9 +211,13 @@ struct perf_dlfilter_al { /* Below members are only populated by resolve_ip() */ __u8 filtered; /* true if this sample event will be filtered out */ const char *comm; + void *priv; /* Private data. Do not change */ }; ---- +Do not assume data referenced by pointers in struct perf_dlfilter_al +is valid (dereferenceable) after 'filter_event' and 'filter_event_early' return. + perf_dlfilter_sample flags ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index c90d55786a028..a5dd1ba0fb5f1 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -377,7 +377,7 @@ ifndef NO_JVMTI PROGRAMS += $(OUTPUT)$(LIBJVMTI) endif -DLFILTERS := dlfilter-test-api-v0.so dlfilter-show-cycles.so +DLFILTERS := dlfilter-test-api-v0.so dlfilter-test-api-v2.so dlfilter-show-cycles.so DLFILTERS := $(patsubst %,$(OUTPUT)dlfilters/%,$(DLFILTERS)) # what 'all' will build and 'install' will install, in perfexecdir diff --git a/tools/perf/dlfilters/dlfilter-test-api-v2.c b/tools/perf/dlfilters/dlfilter-test-api-v2.c new file mode 100644 index 0000000000000..38e593d92920c --- /dev/null +++ b/tools/perf/dlfilters/dlfilter-test-api-v2.c @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Test v2 API for perf --dlfilter shared object + * Copyright (c) 2023, Intel Corporation. + */ +#include +#include +#include +#include + +/* + * Copy v2 API instead of including current API + */ +#include +#include + +/* + * The following macro can be used to determine if this header defines + * perf_dlfilter_sample machine_pid and vcpu. + */ +#define PERF_DLFILTER_HAS_MACHINE_PID + +/* Definitions for perf_dlfilter_sample flags */ +enum { + PERF_DLFILTER_FLAG_BRANCH = 1ULL << 0, + PERF_DLFILTER_FLAG_CALL = 1ULL << 1, + PERF_DLFILTER_FLAG_RETURN = 1ULL << 2, + PERF_DLFILTER_FLAG_CONDITIONAL = 1ULL << 3, + PERF_DLFILTER_FLAG_SYSCALLRET = 1ULL << 4, + PERF_DLFILTER_FLAG_ASYNC = 1ULL << 5, + PERF_DLFILTER_FLAG_INTERRUPT = 1ULL << 6, + PERF_DLFILTER_FLAG_TX_ABORT = 1ULL << 7, + PERF_DLFILTER_FLAG_TRACE_BEGIN = 1ULL << 8, + PERF_DLFILTER_FLAG_TRACE_END = 1ULL << 9, + PERF_DLFILTER_FLAG_IN_TX = 1ULL << 10, + PERF_DLFILTER_FLAG_VMENTRY = 1ULL << 11, + PERF_DLFILTER_FLAG_VMEXIT = 1ULL << 12, +}; + +/* + * perf sample event information (as per perf script and ) + */ +struct perf_dlfilter_sample { + __u32 size; /* Size of this structure (for compatibility checking) */ + __u16 ins_lat; /* Refer PERF_SAMPLE_WEIGHT_TYPE in */ + __u16 p_stage_cyc; /* Refer PERF_SAMPLE_WEIGHT_TYPE in */ + __u64 ip; + __s32 pid; + __s32 tid; + __u64 time; + __u64 addr; + __u64 id; + __u64 stream_id; + __u64 period; + __u64 weight; /* Refer PERF_SAMPLE_WEIGHT_TYPE in */ + __u64 transaction; /* Refer PERF_SAMPLE_TRANSACTION in */ + __u64 insn_cnt; /* For instructions-per-cycle (IPC) */ + __u64 cyc_cnt; /* For instructions-per-cycle (IPC) */ + __s32 cpu; + __u32 flags; /* Refer PERF_DLFILTER_FLAG_* above */ + __u64 data_src; /* Refer PERF_SAMPLE_DATA_SRC in */ + __u64 phys_addr; /* Refer PERF_SAMPLE_PHYS_ADDR in */ + __u64 data_page_size; /* Refer PERF_SAMPLE_DATA_PAGE_SIZE in */ + __u64 code_page_size; /* Refer PERF_SAMPLE_CODE_PAGE_SIZE in */ + __u64 cgroup; /* Refer PERF_SAMPLE_CGROUP in */ + __u8 cpumode; /* Refer CPUMODE_MASK etc in */ + __u8 addr_correlates_sym; /* True => resolve_addr() can be called */ + __u16 misc; /* Refer perf_event_header in */ + __u32 raw_size; /* Refer PERF_SAMPLE_RAW in */ + const void *raw_data; /* Refer PERF_SAMPLE_RAW in */ + __u64 brstack_nr; /* Number of brstack entries */ + const struct perf_branch_entry *brstack; /* Refer */ + __u64 raw_callchain_nr; /* Number of raw_callchain entries */ + const __u64 *raw_callchain; /* Refer */ + const char *event; + __s32 machine_pid; + __s32 vcpu; +}; + +/* + * Address location (as per perf script) + */ +struct perf_dlfilter_al { + __u32 size; /* Size of this structure (for compatibility checking) */ + __u32 symoff; + const char *sym; + __u64 addr; /* Mapped address (from dso) */ + __u64 sym_start; + __u64 sym_end; + const char *dso; + __u8 sym_binding; /* STB_LOCAL, STB_GLOBAL or STB_WEAK, refer */ + __u8 is_64_bit; /* Only valid if dso is not NULL */ + __u8 is_kernel_ip; /* True if in kernel space */ + __u32 buildid_size; + __u8 *buildid; + /* Below members are only populated by resolve_ip() */ + __u8 filtered; /* True if this sample event will be filtered out */ + const char *comm; + void *priv; /* Private data (v2 API) */ +}; + +struct perf_dlfilter_fns { + /* Return information about ip */ + const struct perf_dlfilter_al *(*resolve_ip)(void *ctx); + /* Return information about addr (if addr_correlates_sym) */ + const struct perf_dlfilter_al *(*resolve_addr)(void *ctx); + /* Return arguments from --dlarg option */ + char **(*args)(void *ctx, int *dlargc); + /* + * Return information about address (al->size must be set before + * calling). Returns 0 on success, -1 otherwise. Call al_cleanup() + * when 'al' data is no longer needed. + */ + __s32 (*resolve_address)(void *ctx, __u64 address, struct perf_dlfilter_al *al); + /* Return instruction bytes and length */ + const __u8 *(*insn)(void *ctx, __u32 *length); + /* Return source file name and line number */ + const char *(*srcline)(void *ctx, __u32 *line_number); + /* Return perf_event_attr, refer */ + struct perf_event_attr *(*attr)(void *ctx); + /* Read object code, return numbers of bytes read */ + __s32 (*object_code)(void *ctx, __u64 ip, void *buf, __u32 len); + /* + * If present (i.e. must check al_cleanup != NULL), call after + * resolve_address() to free any associated resources. (v2 API) + */ + void (*al_cleanup)(void *ctx, struct perf_dlfilter_al *al); + /* Reserved */ + void *(*reserved[119])(void *); +}; + +struct perf_dlfilter_fns perf_dlfilter_fns; + +static int verbose; + +#define pr_debug(fmt, ...) do { \ + if (verbose > 0) \ + fprintf(stderr, fmt, ##__VA_ARGS__); \ + } while (0) + +static int test_fail(const char *msg) +{ + pr_debug("%s\n", msg); + return -1; +} + +#define CHECK(x) do { \ + if (!(x)) \ + return test_fail("Check '" #x "' failed\n"); \ + } while (0) + +struct filter_data { + __u64 ip; + __u64 addr; + int do_early; + int early_filter_cnt; + int filter_cnt; +}; + +static struct filter_data *filt_dat; + +int start(void **data, void *ctx) +{ + int dlargc; + char **dlargv; + struct filter_data *d; + static bool called; + + verbose = 1; + + CHECK(!filt_dat && !called); + called = true; + + d = calloc(1, sizeof(*d)); + if (!d) + test_fail("Failed to allocate memory"); + filt_dat = d; + *data = d; + + dlargv = perf_dlfilter_fns.args(ctx, &dlargc); + + CHECK(dlargc == 6); + CHECK(!strcmp(dlargv[0], "first")); + verbose = strtol(dlargv[1], NULL, 0); + d->ip = strtoull(dlargv[2], NULL, 0); + d->addr = strtoull(dlargv[3], NULL, 0); + d->do_early = strtol(dlargv[4], NULL, 0); + CHECK(!strcmp(dlargv[5], "last")); + + pr_debug("%s API\n", __func__); + + return 0; +} + +#define CHECK_SAMPLE(x) do { \ + if (sample->x != expected.x) \ + return test_fail("'" #x "' not expected value\n"); \ + } while (0) + +static int check_sample(struct filter_data *d, const struct perf_dlfilter_sample *sample) +{ + struct perf_dlfilter_sample expected = { + .ip = d->ip, + .pid = 12345, + .tid = 12346, + .time = 1234567890, + .addr = d->addr, + .id = 99, + .stream_id = 101, + .period = 543212345, + .cpu = 31, + .cpumode = PERF_RECORD_MISC_USER, + .addr_correlates_sym = 1, + .misc = PERF_RECORD_MISC_USER, + }; + + CHECK(sample->size >= sizeof(struct perf_dlfilter_sample)); + + CHECK_SAMPLE(ip); + CHECK_SAMPLE(pid); + CHECK_SAMPLE(tid); + CHECK_SAMPLE(time); + CHECK_SAMPLE(addr); + CHECK_SAMPLE(id); + CHECK_SAMPLE(stream_id); + CHECK_SAMPLE(period); + CHECK_SAMPLE(cpu); + CHECK_SAMPLE(cpumode); + CHECK_SAMPLE(addr_correlates_sym); + CHECK_SAMPLE(misc); + + CHECK(!sample->raw_data); + CHECK_SAMPLE(brstack_nr); + CHECK(!sample->brstack); + CHECK_SAMPLE(raw_callchain_nr); + CHECK(!sample->raw_callchain); + +#define EVENT_NAME "branches:" + CHECK(!strncmp(sample->event, EVENT_NAME, strlen(EVENT_NAME))); + + return 0; +} + +static int check_al(void *ctx) +{ + const struct perf_dlfilter_al *al; + + al = perf_dlfilter_fns.resolve_ip(ctx); + if (!al) + return test_fail("resolve_ip() failed"); + + CHECK(al->sym && !strcmp("foo", al->sym)); + CHECK(!al->symoff); + + return 0; +} + +static int check_addr_al(void *ctx) +{ + const struct perf_dlfilter_al *addr_al; + + addr_al = perf_dlfilter_fns.resolve_addr(ctx); + if (!addr_al) + return test_fail("resolve_addr() failed"); + + CHECK(addr_al->sym && !strcmp("bar", addr_al->sym)); + CHECK(!addr_al->symoff); + + return 0; +} + +static int check_address_al(void *ctx, const struct perf_dlfilter_sample *sample) +{ + struct perf_dlfilter_al address_al; + const struct perf_dlfilter_al *al; + + al = perf_dlfilter_fns.resolve_ip(ctx); + if (!al) + return test_fail("resolve_ip() failed"); + + address_al.size = sizeof(address_al); + if (perf_dlfilter_fns.resolve_address(ctx, sample->ip, &address_al)) + return test_fail("resolve_address() failed"); + + CHECK(address_al.sym && al->sym); + CHECK(!strcmp(address_al.sym, al->sym)); + CHECK(address_al.addr == al->addr); + CHECK(address_al.sym_start == al->sym_start); + CHECK(address_al.sym_end == al->sym_end); + CHECK(address_al.dso && al->dso); + CHECK(!strcmp(address_al.dso, al->dso)); + + /* al_cleanup() is v2 API so may not be present */ + if (perf_dlfilter_fns.al_cleanup) + perf_dlfilter_fns.al_cleanup(ctx, &address_al); + + return 0; +} + +static int check_attr(void *ctx) +{ + struct perf_event_attr *attr = perf_dlfilter_fns.attr(ctx); + + CHECK(attr); + CHECK(attr->type == PERF_TYPE_HARDWARE); + CHECK(attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS); + + return 0; +} + +static int do_checks(void *data, const struct perf_dlfilter_sample *sample, void *ctx, bool early) +{ + struct filter_data *d = data; + + CHECK(data && filt_dat == data); + + if (early) { + CHECK(!d->early_filter_cnt); + d->early_filter_cnt += 1; + } else { + CHECK(!d->filter_cnt); + CHECK(d->early_filter_cnt); + CHECK(d->do_early != 2); + d->filter_cnt += 1; + } + + if (check_sample(data, sample)) + return -1; + + if (check_attr(ctx)) + return -1; + + if (early && !d->do_early) + return 0; + + if (check_al(ctx) || check_addr_al(ctx) || check_address_al(ctx, sample)) + return -1; + + if (early) + return d->do_early == 2; + + return 1; +} + +int filter_event_early(void *data, const struct perf_dlfilter_sample *sample, void *ctx) +{ + pr_debug("%s API\n", __func__); + + return do_checks(data, sample, ctx, true); +} + +int filter_event(void *data, const struct perf_dlfilter_sample *sample, void *ctx) +{ + pr_debug("%s API\n", __func__); + + return do_checks(data, sample, ctx, false); +} + +int stop(void *data, void *ctx) +{ + static bool called; + + pr_debug("%s API\n", __func__); + + CHECK(data && filt_dat == data && !called); + called = true; + + free(data); + filt_dat = NULL; + return 0; +} + +const char *filter_description(const char **long_description) +{ + *long_description = "Filter used by the 'dlfilter C API' perf test"; + return "dlfilter to test v2 C API"; +} diff --git a/tools/perf/include/perf/perf_dlfilter.h b/tools/perf/include/perf/perf_dlfilter.h index a26e2f129f83e..16fc4568ac53b 100644 --- a/tools/perf/include/perf/perf_dlfilter.h +++ b/tools/perf/include/perf/perf_dlfilter.h @@ -91,6 +91,7 @@ struct perf_dlfilter_al { /* Below members are only populated by resolve_ip() */ __u8 filtered; /* True if this sample event will be filtered out */ const char *comm; + void *priv; /* Private data. Do not change */ }; struct perf_dlfilter_fns { @@ -102,7 +103,8 @@ struct perf_dlfilter_fns { char **(*args)(void *ctx, int *dlargc); /* * Return information about address (al->size must be set before - * calling). Returns 0 on success, -1 otherwise. + * calling). Returns 0 on success, -1 otherwise. Call al_cleanup() + * when 'al' data is no longer needed. */ __s32 (*resolve_address)(void *ctx, __u64 address, struct perf_dlfilter_al *al); /* Return instruction bytes and length */ @@ -113,8 +115,13 @@ struct perf_dlfilter_fns { struct perf_event_attr *(*attr)(void *ctx); /* Read object code, return numbers of bytes read */ __s32 (*object_code)(void *ctx, __u64 ip, void *buf, __u32 len); + /* + * If present (i.e. must check al_cleanup != NULL), call after + * resolve_address() to free any associated resources. + */ + void (*al_cleanup)(void *ctx, struct perf_dlfilter_al *al); /* Reserved */ - void *(*reserved[120])(void *); + void *(*reserved[119])(void *); }; /* diff --git a/tools/perf/tests/dlfilter-test.c b/tools/perf/tests/dlfilter-test.c index 086fd2179e41f..da3a9b50b1b1f 100644 --- a/tools/perf/tests/dlfilter-test.c +++ b/tools/perf/tests/dlfilter-test.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Test dlfilter C API. A perf.data file is synthesized and then processed - * by perf script with a dlfilter named dlfilter-test-api-v0.so. Also a C file + * by perf script with dlfilters named dlfilter-test-api-v*.so. Also a C file * is compiled to provide a dso to match the synthesized perf.data file. */ @@ -37,6 +37,8 @@ #define MAP_START 0x400000 +#define DLFILTER_TEST_NAME_MAX 128 + struct test_data { struct perf_tool tool; struct machine *machine; @@ -45,6 +47,8 @@ struct test_data { u64 bar; u64 ip; u64 addr; + char name[DLFILTER_TEST_NAME_MAX]; + char desc[DLFILTER_TEST_NAME_MAX]; char perf[PATH_MAX]; char perf_data_file_name[PATH_MAX]; char c_file_name[PATH_MAX]; @@ -215,7 +219,7 @@ static int write_prog(char *file_name) return err ? -1 : 0; } -static int get_dlfilters_path(char *buf, size_t sz) +static int get_dlfilters_path(const char *name, char *buf, size_t sz) { char perf[PATH_MAX]; char path[PATH_MAX]; @@ -224,12 +228,12 @@ static int get_dlfilters_path(char *buf, size_t sz) perf_exe(perf, sizeof(perf)); perf_path = dirname(perf); - snprintf(path, sizeof(path), "%s/dlfilters/dlfilter-test-api-v0.so", perf_path); + snprintf(path, sizeof(path), "%s/dlfilters/%s", perf_path, name); if (access(path, R_OK)) { exec_path = get_argv_exec_path(); if (!exec_path) return -1; - snprintf(path, sizeof(path), "%s/dlfilters/dlfilter-test-api-v0.so", exec_path); + snprintf(path, sizeof(path), "%s/dlfilters/%s", exec_path, name); free(exec_path); if (access(path, R_OK)) return -1; @@ -244,9 +248,9 @@ static int check_filter_desc(struct test_data *td) char *desc = NULL; int ret; - if (get_filter_desc(td->dlfilters, "dlfilter-test-api-v0.so", &desc, &long_desc) && + if (get_filter_desc(td->dlfilters, td->name, &desc, &long_desc) && long_desc && !strcmp(long_desc, "Filter used by the 'dlfilter C API' perf test") && - desc && !strcmp(desc, "dlfilter to test v0 C API")) + desc && !strcmp(desc, td->desc)) ret = 0; else ret = -1; @@ -284,7 +288,7 @@ static int get_ip_addr(struct test_data *td) static int do_run_perf_script(struct test_data *td, int do_early) { return system_cmd("%s script -i %s " - "--dlfilter %s/dlfilter-test-api-v0.so " + "--dlfilter %s/%s " "--dlarg first " "--dlarg %d " "--dlarg %" PRIu64 " " @@ -292,7 +296,7 @@ static int do_run_perf_script(struct test_data *td, int do_early) "--dlarg %d " "--dlarg last", td->perf, td->perf_data_file_name, td->dlfilters, - verbose, td->ip, td->addr, do_early); + td->name, verbose, td->ip, td->addr, do_early); } static int run_perf_script(struct test_data *td) @@ -321,7 +325,7 @@ static int test__dlfilter_test(struct test_data *td) u64 id = 99; int err; - if (get_dlfilters_path(td->dlfilters, PATH_MAX)) + if (get_dlfilters_path(td->name, td->dlfilters, PATH_MAX)) return test_result("dlfilters not found", TEST_SKIP); if (check_filter_desc(td)) @@ -399,14 +403,18 @@ static void test_data__free(struct test_data *td) } } -static int test__dlfilter(struct test_suite *test __maybe_unused, int subtest __maybe_unused) +static int test__dlfilter_ver(int ver) { struct test_data td = {.fd = -1}; int pid = getpid(); int err; + pr_debug("\n-- Testing version %d API --\n", ver); + perf_exe(td.perf, sizeof(td.perf)); + snprintf(td.name, sizeof(td.name), "dlfilter-test-api-v%d.so", ver); + snprintf(td.desc, sizeof(td.desc), "dlfilter to test v%d C API", ver); snprintf(td.perf_data_file_name, PATH_MAX, "/tmp/dlfilter-test-%u-perf-data", pid); snprintf(td.c_file_name, PATH_MAX, "/tmp/dlfilter-test-%u-prog.c", pid); snprintf(td.prog_file_name, PATH_MAX, "/tmp/dlfilter-test-%u-prog", pid); @@ -416,4 +424,14 @@ static int test__dlfilter(struct test_suite *test __maybe_unused, int subtest __ return err; } +static int test__dlfilter(struct test_suite *test __maybe_unused, int subtest __maybe_unused) +{ + int err = test__dlfilter_ver(0); + + if (err) + return err; + /* No test for version 1 */ + return test__dlfilter_ver(2); +} + DEFINE_SUITE("dlfilter C API", dlfilter); diff --git a/tools/perf/util/dlfilter.c b/tools/perf/util/dlfilter.c index 798a53d7e6c9d..e0f822ebb9b97 100644 --- a/tools/perf/util/dlfilter.c +++ b/tools/perf/util/dlfilter.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include "debug.h" #include "event.h" @@ -63,6 +65,7 @@ static void al_to_d_al(struct addr_location *al, struct perf_dlfilter_al *d_al) d_al->addr = al->addr; d_al->comm = NULL; d_al->filtered = 0; + d_al->priv = NULL; } static struct addr_location *get_al(struct dlfilter *d) @@ -151,6 +154,11 @@ static char **dlfilter__args(void *ctx, int *dlargc) return d->dlargv; } +static bool has_priv(struct perf_dlfilter_al *d_al_p) +{ + return d_al_p->size >= offsetof(struct perf_dlfilter_al, priv) + sizeof(d_al_p->priv); +} + static __s32 dlfilter__resolve_address(void *ctx, __u64 address, struct perf_dlfilter_al *d_al_p) { struct dlfilter *d = (struct dlfilter *)ctx; @@ -177,9 +185,29 @@ static __s32 dlfilter__resolve_address(void *ctx, __u64 address, struct perf_dlf memcpy(d_al_p, &d_al, min((size_t)sz, sizeof(d_al))); d_al_p->size = sz; + if (has_priv(d_al_p)) + d_al_p->priv = memdup(&al, sizeof(al)); + return 0; } +static void dlfilter__al_cleanup(void *ctx __maybe_unused, struct perf_dlfilter_al *d_al_p) +{ + struct addr_location *al; + + /* Ensure backward compatibility */ + if (!has_priv(d_al_p) || !d_al_p->priv) + return; + + al = d_al_p->priv; + + d_al_p->priv = NULL; + + addr_location__exit(al); + + free(al); +} + static const __u8 *dlfilter__insn(void *ctx, __u32 *len) { struct dlfilter *d = (struct dlfilter *)ctx; @@ -297,6 +325,7 @@ static const struct perf_dlfilter_fns perf_dlfilter_fns = { .resolve_addr = dlfilter__resolve_addr, .args = dlfilter__args, .resolve_address = dlfilter__resolve_address, + .al_cleanup = dlfilter__al_cleanup, .insn = dlfilter__insn, .srcline = dlfilter__srcline, .attr = dlfilter__attr, -- GitLab From a4b6452af7f481d9a36037dd7c76c2d394992ad5 Mon Sep 17 00:00:00 2001 From: James Clark Date: Fri, 11 Aug 2023 15:39:18 +0100 Subject: [PATCH 1097/3445] perf cs-etm: Don't duplicate FIELD_GET() linux/bitfield.h can be included as long as linux/kernel.h is included first, so change the order of the includes and drop the duplicate macro. Reviewed-by: John Garry Signed-off-by: James Clark Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andrii Nakryiko Cc: Eduard Zingerman Cc: Ian Rogers Cc: Ingo Molnar Cc: Jing Zhang Cc: Jiri Olsa Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Mike Leach Cc: Namhyung Kim Cc: Nick Forrington Cc: Peter Zijlstra Cc: Rob Herring Cc: Sohom Datta Cc: Suzuki Poulouse Cc: Will Deacon Cc: coresight@lists.linaro.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20230811144017.491628-2-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/cs-etm.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index 1419b40dfbe80..9729d006550d9 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -6,10 +6,11 @@ * Author: Mathieu Poirier */ +#include +#include #include #include #include -#include #include #include #include @@ -281,17 +282,6 @@ static int cs_etm__metadata_set_trace_id(u8 trace_chan_id, u64 *cpu_metadata) return 0; } -/* - * FIELD_GET (linux/bitfield.h) not available outside kernel code, - * and the header contains too many dependencies to just copy over, - * so roll our own based on the original - */ -#define __bf_shf(x) (__builtin_ffsll(x) - 1) -#define FIELD_GET(_mask, _reg) \ - ({ \ - (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \ - }) - /* * Get a metadata for a specific cpu from an array. * -- GitLab From ab3744007d51420dd63d5323acbe7abbb843ba63 Mon Sep 17 00:00:00 2001 From: James Clark Date: Fri, 11 Aug 2023 15:39:21 +0100 Subject: [PATCH 1098/3445] perf vendor events arm64: Update scale units and descriptions of common topdown metrics Metrics will be published here [1] going forwards, but they have slightly different scale units. To allow autogenerated metrics to be added more easily, update the scale units to match. The more detailed descriptions have also been taken and added to the common file. [1]: https://gitlab.arm.com/telemetry-solution/telemetry-solution/-/tree/main/data/pmu/cpu/ Reviewed-by: John Garry Signed-off-by: James Clark Acked-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andrii Nakryiko Cc: Eduard Zingerman Cc: Ingo Molnar Cc: Jing Zhang Cc: Jiri Olsa Cc: Kajol Jain Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Mike Leach Cc: Namhyung Kim Cc: Nick Forrington Cc: Peter Zijlstra Cc: Rob Herring Cc: Sohom Datta Cc: Suzuki Poulouse Cc: Will Deacon Cc: coresight@lists.linaro.org Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20230811144017.491628-5-james.clark@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/pmu-events/arch/arm64/sbsa.json | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tools/perf/pmu-events/arch/arm64/sbsa.json b/tools/perf/pmu-events/arch/arm64/sbsa.json index f90b338261ac5..4eed79a28f6ee 100644 --- a/tools/perf/pmu-events/arch/arm64/sbsa.json +++ b/tools/perf/pmu-events/arch/arm64/sbsa.json @@ -1,34 +1,34 @@ [ { - "MetricExpr": "stall_slot_frontend / (#slots * cpu_cycles)", - "BriefDescription": "Frontend bound L1 topdown metric", + "MetricExpr": "100 * (stall_slot_frontend / (#slots * cpu_cycles))", + "BriefDescription": "This metric is the percentage of total slots that were stalled due to resource constraints in the frontend of the processor.", "DefaultMetricgroupName": "TopdownL1", "MetricGroup": "Default;TopdownL1", "MetricName": "frontend_bound", - "ScaleUnit": "100%" + "ScaleUnit": "1percent of slots" }, { - "MetricExpr": "(1 - op_retired / op_spec) * (1 - stall_slot / (#slots * cpu_cycles))", - "BriefDescription": "Bad speculation L1 topdown metric", + "MetricExpr": "100 * ((1 - op_retired / op_spec) * (1 - stall_slot / (#slots * cpu_cycles)))", + "BriefDescription": "This metric is the percentage of total slots that executed operations and didn't retire due to a pipeline flush.\nThis indicates cycles that were utilized but inefficiently.", "DefaultMetricgroupName": "TopdownL1", "MetricGroup": "Default;TopdownL1", "MetricName": "bad_speculation", - "ScaleUnit": "100%" + "ScaleUnit": "1percent of slots" }, { - "MetricExpr": "(op_retired / op_spec) * (1 - stall_slot / (#slots * cpu_cycles))", - "BriefDescription": "Retiring L1 topdown metric", + "MetricExpr": "100 * ((op_retired / op_spec) * (1 - stall_slot / (#slots * cpu_cycles)))", + "BriefDescription": "This metric is the percentage of total slots that retired operations, which indicates cycles that were utilized efficiently.", "DefaultMetricgroupName": "TopdownL1", "MetricGroup": "Default;TopdownL1", "MetricName": "retiring", - "ScaleUnit": "100%" + "ScaleUnit": "1percent of slots" }, { - "MetricExpr": "stall_slot_backend / (#slots * cpu_cycles)", - "BriefDescription": "Backend Bound L1 topdown metric", + "MetricExpr": "100 * (stall_slot_backend / (#slots * cpu_cycles))", + "BriefDescription": "This metric is the percentage of total slots that were stalled due to resource constraints in the backend of the processor.", "DefaultMetricgroupName": "TopdownL1", "MetricGroup": "Default;TopdownL1", "MetricName": "backend_bound", - "ScaleUnit": "100%" + "ScaleUnit": "1percent of slots" } ] -- GitLab From 4d6af37cafad69ff93f62db80d5a3daa9ac3223f Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 15 Jun 2023 12:58:19 +0200 Subject: [PATCH 1099/3445] rtc: isl12022: remove wrong warning for low battery level There are multiple problems with this warning. First of all, it triggers way too often, in fact nearly on every boot, because the SR_LBAT85/SR_LBAT75 bits have another meaning when in battery backup mode. Quoting from the data sheet: LOW BATTERY INDICATOR 85% BIT (LBAT85) In Normal Mode (VDD), this bit indicates when the battery level has dropped below the pre-selected trip levels. [...] The LBAT85 detection happens automatically once every minute when seconds register reaches 59. In Battery Mode (VBAT), this bit indicates the device has entered into battery mode by polling once every 10 minutes. The LBAT85 detection happens automatically once when the minute register reaches x9h or x0h minutes. Similar wording applies to the LBAT75 bit. This means that if the device is powered off for more than 10 minutes, the LBAT85 bit is guaranteed to be set. Upon power-on, unless we're close enough to the end of a minute and/or the boot is slow enough that the second register passes 59, the LBAT85 bit is still set when the kernel (or early userspace) reads the RTC to set the system's wallclock time. Another minor problem is with the bit logic. If the 75% level is reached, logically we're also below 85%, so both bits would most likely be set. So even if the battery is below 75%, the warning would still say "voltage dropped below 85%". A third problem is that the driver and current DT binding offer no way to indicate the nominal battery level and/or settings of the Battery Level Monitor Trip Bits. Since the default value of the VB85TP[2:0] and VB75TP[2:0] bits are 000, this means the actual setting of the LBAT85/LBAT75 bits in VDD mode doesn't happen until the battery is below 2.125V/1.875V, which for a standard 3V battery is way too late. A fourth problem is emitting this warning from ->read_time: util-linux' hwclock will, in the absence of support for getting an interrupt when the seconds counter is updated, issue ioctl(RTC_RD_TIME) in a busy-loop until it sees a change in the seconds field. In that case, if the battery low bits are set (either genuinely, more than a minute after boot, due to the battery actually being low, or as above, bogusly shortly after boot), the kernel log is swamped with hundreds of identical warnings. Subsequent patches will add such bindings and driver support, and also proper support for RTC_VL_READ. For now, remove the broken warning. Signed-off-by: Rasmus Villemoes Link: https://lore.kernel.org/r/20230615105826.411953-2-linux@rasmusvillemoes.dk Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl12022.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index a613257d1574d..a39aea90230fe 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -141,12 +141,6 @@ static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm) if (ret) return ret; - if (buf[ISL12022_REG_SR] & (ISL12022_SR_LBAT85 | ISL12022_SR_LBAT75)) { - dev_warn(dev, - "voltage dropped below %u%%, date and time is not reliable.\n", - buf[ISL12022_REG_SR] & ISL12022_SR_LBAT85 ? 85 : 75); - } - dev_dbg(dev, "raw data is sec=%02x, min=%02x, hr=%02x, mday=%02x, mon=%02x, year=%02x, wday=%02x, sr=%02x, int=%02x", buf[ISL12022_REG_SC], -- GitLab From ffc005280a47030d16cbbf3105c75d3562dba5a8 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 15 Jun 2023 12:58:20 +0200 Subject: [PATCH 1100/3445] dt-bindings: rtc: Move isil,isl12022 from trivial-rtc.yaml into own schema file Move the isil,isl12022 RTC bindings from trivial-rtc.yaml into its own intersil,isl12022.yaml file, in preparation for adding more bindings. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Rasmus Villemoes Link: https://lore.kernel.org/r/20230615105826.411953-3-linux@rasmusvillemoes.dk Signed-off-by: Alexandre Belloni --- .../bindings/rtc/intersil,isl12022.yaml | 45 +++++++++++++++++++ .../devicetree/bindings/rtc/trivial-rtc.yaml | 2 - 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml diff --git a/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml b/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml new file mode 100644 index 0000000000000..054d3fc649ba3 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/intersil,isl12022.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Intersil ISL12022 Real-time Clock + +maintainers: + - Alexandre Belloni + +properties: + compatible: + const: isil,isl12022 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + +allOf: + - $ref: rtc.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + rtc@6f { + compatible = "isil,isl12022"; + reg = <0x6f>; + interrupts-extended = <&gpio1 5 IRQ_TYPE_LEVEL_LOW>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml index 9af77f21bb7f4..2a65f31ac5a05 100644 --- a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml @@ -45,8 +45,6 @@ properties: - isil,isl1208 # Intersil ISL1218 Low Power RTC with Battery Backed SRAM - isil,isl1218 - # Intersil ISL12022 Real-time Clock - - isil,isl12022 # Real Time Clock Module with I2C-Bus - microcrystal,rv3029 # Real Time Clock -- GitLab From 69b569c124ffa698de25d039018fe86313c46c84 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 15 Jun 2023 12:58:21 +0200 Subject: [PATCH 1101/3445] dt-bindings: rtc: isl12022: add bindings for battery alarm trip levels The isl12022 has a built-in support for monitoring the voltage of the backup battery, and setting bits in the status register when that voltage drops below two predetermined levels (usually 85% and 75% of the nominal voltage). However, since it can operate at wide range of battery voltages (2.5V - 5.5V), one must configure those trip levels according to which battery is used on a given board. Add bindings for defining these two trip levels. While the register and bit names suggest that they should correspond to 85% and 75% of the nominal battery voltage, the data sheet also says There are total of 7 levels that could be selected for the first alarm. Any of the of levels could be selected as the first alarm with no reference as to nominal Battery voltage level. Hence this provides the hardware designer the ability to choose values based on the discharge characteristics of the battery chosen for the given product, rather than just having one battery-microvolt property and having the driver choose levels close to 0.85/0.75 times that. Signed-off-by: Rasmus Villemoes Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230615105826.411953-4-linux@rasmusvillemoes.dk Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/intersil,isl12022.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml b/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml index 054d3fc649ba3..3c6c07aaa78f0 100644 --- a/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml +++ b/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml @@ -19,6 +19,14 @@ properties: interrupts: maxItems: 1 + isil,battery-trip-levels-microvolt: + description: + The battery voltages at which the first alarm and second alarm + should trigger (normally ~85% and ~75% of nominal V_BAT). + items: + - enum: [2125000, 2295000, 2550000, 2805000, 3060000, 4250000, 4675000] + - enum: [1875000, 2025000, 2250000, 2475000, 2700000, 3750000, 4125000] + required: - compatible - reg @@ -39,6 +47,7 @@ examples: compatible = "isil,isl12022"; reg = <0x6f>; interrupts-extended = <&gpio1 5 IRQ_TYPE_LEVEL_LOW>; + isil,battery-trip-levels-microvolt = <2550000>, <2250000>; }; }; -- GitLab From 2caeb566baabb65add7d99ca6d8bfd566fe91582 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 15 Jun 2023 12:58:22 +0200 Subject: [PATCH 1102/3445] rtc: isl12022: add support for trip level DT binding Implement support for using the values given in the isil,battery-trip-levels-microvolt property to set appropriate values in the VB85TP/VB75TP bits in the PWR_VBAT register. Signed-off-by: Rasmus Villemoes Link: https://lore.kernel.org/r/20230615105826.411953-5-linux@rasmusvillemoes.dk Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl12022.c | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index a39aea90230fe..a50eed4e40281 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -31,6 +32,8 @@ #define ISL12022_REG_SR 0x07 #define ISL12022_REG_INT 0x08 +#define ISL12022_REG_PWR_VBAT 0x0a + #define ISL12022_REG_BETA 0x0d #define ISL12022_REG_TEMP_L 0x28 @@ -42,6 +45,9 @@ #define ISL12022_INT_WRTC (1 << 6) +#define ISL12022_REG_VB85_MASK GENMASK(5, 3) +#define ISL12022_REG_VB75_MASK GENMASK(2, 0) + #define ISL12022_BETA_TSE (1 << 7) static umode_t isl12022_hwmon_is_visible(const void *data, @@ -209,6 +215,38 @@ static const struct regmap_config regmap_config = { .use_single_write = true, }; +static const u32 trip_levels[2][7] = { + { 2125000, 2295000, 2550000, 2805000, 3060000, 4250000, 4675000 }, + { 1875000, 2025000, 2250000, 2475000, 2700000, 3750000, 4125000 }, +}; + +static void isl12022_set_trip_levels(struct device *dev) +{ + struct regmap *regmap = dev_get_drvdata(dev); + u32 levels[2] = {0, 0}; + int ret, i, j, x[2]; + u8 val, mask; + + device_property_read_u32_array(dev, "isil,battery-trip-levels-microvolt", + levels, 2); + + for (i = 0; i < 2; i++) { + for (j = 0; j < ARRAY_SIZE(trip_levels[i]) - 1; j++) { + if (levels[i] <= trip_levels[i][j]) + break; + } + x[i] = j; + } + + val = FIELD_PREP(ISL12022_REG_VB85_MASK, x[0]) | + FIELD_PREP(ISL12022_REG_VB75_MASK, x[1]); + mask = ISL12022_REG_VB85_MASK | ISL12022_REG_VB75_MASK; + + ret = regmap_update_bits(regmap, ISL12022_REG_PWR_VBAT, mask, val); + if (ret) + dev_warn(dev, "unable to set battery alarm levels: %d\n", ret); +} + static int isl12022_probe(struct i2c_client *client) { struct rtc_device *rtc; @@ -225,6 +263,7 @@ static int isl12022_probe(struct i2c_client *client) dev_set_drvdata(&client->dev, regmap); + isl12022_set_trip_levels(&client->dev); isl12022_hwmon_register(&client->dev); rtc = devm_rtc_allocate_device(&client->dev); -- GitLab From eccebd813874b748ac4e79a9fe4c7290117ad3be Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 15 Jun 2023 12:58:23 +0200 Subject: [PATCH 1103/3445] rtc: isl12022: implement RTC_VL_READ ioctl Hook up support for reading the values of the SR_LBAT85 and SR_LBAT75 bits. Translate the former to "battery low", and the latter to "battery empty or not-present". Signed-off-by: Rasmus Villemoes Link: https://lore.kernel.org/r/20230615105826.411953-6-linux@rasmusvillemoes.dk Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl12022.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index a50eed4e40281..0ed28b57bcd89 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -204,7 +204,34 @@ static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm) return regmap_bulk_write(regmap, ISL12022_REG_SC, buf, sizeof(buf)); } +static int isl12022_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + struct regmap *regmap = dev_get_drvdata(dev); + u32 user, val; + int ret; + + switch (cmd) { + case RTC_VL_READ: + ret = regmap_read(regmap, ISL12022_REG_SR, &val); + if (ret) + return ret; + + user = 0; + if (val & ISL12022_SR_LBAT85) + user |= RTC_VL_BACKUP_LOW; + + if (val & ISL12022_SR_LBAT75) + user |= RTC_VL_BACKUP_EMPTY; + + return put_user(user, (u32 __user *)arg); + + default: + return -ENOIOCTLCMD; + } +} + static const struct rtc_class_ops isl12022_rtc_ops = { + .ioctl = isl12022_rtc_ioctl, .read_time = isl12022_rtc_read_time, .set_time = isl12022_rtc_set_time, }; -- GitLab From a11b6c460620f7fb5fae4c3aee5a5ba2e1e1129b Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 15 Jun 2023 12:58:24 +0200 Subject: [PATCH 1104/3445] rtc: isl12022: trigger battery level detection during probe Since the meaning of the SR_LBAT85 and SR_LBAT75 bits are different in battery backup mode, they may very well be set after power on, and stay set for up to a minute (i.e. until the battery detection in VDD mode happens when the seconds counter hits 59). This would mean that userspace doing a ioctl(RTC_VL_READ) early on could get a false positive. The battery level detection can also be triggered by explicitly writing a 1 to the TSE bit in the BETA register. Do that once during boot. Empirically, this does not immediately update the bits in the status register (i.e., an immediate read of SR after this write can still show stale values), but the update is done after a few milliseconds, so certainly before the RTC device gets registered and userspace has a chance of doing the ioctl() on this device. Signed-off-by: Rasmus Villemoes Link: https://lore.kernel.org/r/20230615105826.411953-7-linux@rasmusvillemoes.dk Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl12022.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index 0ed28b57bcd89..a816c5447295d 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -272,6 +272,16 @@ static void isl12022_set_trip_levels(struct device *dev) ret = regmap_update_bits(regmap, ISL12022_REG_PWR_VBAT, mask, val); if (ret) dev_warn(dev, "unable to set battery alarm levels: %d\n", ret); + + /* + * Force a write of the TSE bit in the BETA register, in order + * to trigger an update of the LBAT75 and LBAT85 bits in the + * status register. In battery backup mode, those bits have + * another meaning, so without this, they may contain stale + * values for up to a minute after power-on. + */ + regmap_write_bits(regmap, ISL12022_REG_BETA, + ISL12022_BETA_TSE, ISL12022_BETA_TSE); } static int isl12022_probe(struct i2c_client *client) -- GitLab From ab246c897be0bdf981f776399ca62b5ec4b8138f Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 15 Jun 2023 12:58:25 +0200 Subject: [PATCH 1105/3445] dt-bindings: rtc: isl12022: add #clock-cells property The isl12022 has a dual-purpose irq/f_out pin, which can either be used as an interrupt or clock output. Signed-off-by: Rasmus Villemoes Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230615105826.411953-8-linux@rasmusvillemoes.dk Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/intersil,isl12022.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml b/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml index 3c6c07aaa78f0..c2d1441ef273f 100644 --- a/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml +++ b/Documentation/devicetree/bindings/rtc/intersil,isl12022.yaml @@ -19,6 +19,9 @@ properties: interrupts: maxItems: 1 + '#clock-cells': + const: 0 + isil,battery-trip-levels-microvolt: description: The battery voltages at which the first alarm and second alarm @@ -33,6 +36,13 @@ required: allOf: - $ref: rtc.yaml# + # If #clock-cells is present, interrupts must not be present + - if: + required: + - '#clock-cells' + then: + properties: + interrupts: false unevaluatedProperties: false -- GitLab From d57d12db774820819d0e591548a56b5cfc95f82a Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 15 Jun 2023 12:58:26 +0200 Subject: [PATCH 1106/3445] rtc: isl12022: implement support for the #clock-cells DT property If device tree implies that the chip's IRQ/F_OUT pin is used as a clock, expose that in the driver. For now, pretend it is a fixed-rate (32kHz) clock; if other use cases appear the driver can be updated to provide its own clk_ops etc. When the clock output is not used on a given board, one can prolong the battery life by ensuring that the FOx bits are 0. For the hardware I'm currently working on, the RTC draws 1.2uA with the FOx bits at their default 0001 value, dropping to 0.88uA when those bits are cleared. Signed-off-by: Rasmus Villemoes Link: https://lore.kernel.org/r/20230615105826.411953-9-linux@rasmusvillemoes.dk Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl12022.c | 44 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index a816c5447295d..4eef7afcc8bcc 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -44,6 +45,9 @@ #define ISL12022_SR_LBAT75 (1 << 1) #define ISL12022_INT_WRTC (1 << 6) +#define ISL12022_INT_FO_MASK GENMASK(3, 0) +#define ISL12022_INT_FO_OFF 0x0 +#define ISL12022_INT_FO_32K 0x1 #define ISL12022_REG_VB85_MASK GENMASK(5, 3) #define ISL12022_REG_VB75_MASK GENMASK(2, 0) @@ -242,6 +246,41 @@ static const struct regmap_config regmap_config = { .use_single_write = true, }; +static int isl12022_register_clock(struct device *dev) +{ + struct regmap *regmap = dev_get_drvdata(dev); + struct clk_hw *hw; + int ret; + + if (!device_property_present(dev, "#clock-cells")) { + /* + * Disabling the F_OUT pin reduces the power + * consumption in battery mode by ~25%. + */ + regmap_update_bits(regmap, ISL12022_REG_INT, ISL12022_INT_FO_MASK, + ISL12022_INT_FO_OFF); + + return 0; + } + + if (!IS_ENABLED(CONFIG_COMMON_CLK)) + return 0; + + /* + * For now, only support a fixed clock of 32768Hz (the reset default). + */ + ret = regmap_update_bits(regmap, ISL12022_REG_INT, + ISL12022_INT_FO_MASK, ISL12022_INT_FO_32K); + if (ret) + return ret; + + hw = devm_clk_hw_register_fixed_rate(dev, "isl12022", NULL, 0, 32768); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw); +} + static const u32 trip_levels[2][7] = { { 2125000, 2295000, 2550000, 2805000, 3060000, 4250000, 4675000 }, { 1875000, 2025000, 2250000, 2475000, 2700000, 3750000, 4125000 }, @@ -288,6 +327,7 @@ static int isl12022_probe(struct i2c_client *client) { struct rtc_device *rtc; struct regmap *regmap; + int ret; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; @@ -300,6 +340,10 @@ static int isl12022_probe(struct i2c_client *client) dev_set_drvdata(&client->dev, regmap); + ret = isl12022_register_clock(&client->dev); + if (ret) + return ret; + isl12022_set_trip_levels(&client->dev); isl12022_hwmon_register(&client->dev); -- GitLab From 737055e11729836fc3d7b26220affad30b4736ec Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 12:38:59 +0200 Subject: [PATCH 1107/3445] rtc: ds1307: fix Wvoid-pointer-to-enum-cast warning 'type' is an enum, thus cast of pointer on 64-bit compile test with W=1 causes: rtc-ds1307.c:1747:18: error: cast to smaller integer type 'enum ds_type' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810103902.151145-1-krzysztof.kozlowski@linaro.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1307.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index cb5acecc11aa4..506b7d1c23970 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -1744,7 +1744,7 @@ static int ds1307_probe(struct i2c_client *client) match = device_get_match_data(&client->dev); if (match) { - ds1307->type = (enum ds_type)match; + ds1307->type = (uintptr_t)match; chip = &chips[ds1307->type]; } else if (id) { chip = &chips[id->driver_data]; -- GitLab From fbbeae0af551b8e5fba6ba128d2190c2a29dce90 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 12:39:00 +0200 Subject: [PATCH 1108/3445] rtc: rv8803: fix Wvoid-pointer-to-enum-cast warning 'type' is an enum, thus cast of pointer on 64-bit compile test with W=1 causes: rtc-rv8803.c:648:18: error: cast to smaller integer type 'enum rv8803_type' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810103902.151145-2-krzysztof.kozlowski@linaro.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rv8803.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index fd8ab0b2f731b..1a3ec1bb5b814 100644 --- a/drivers/rtc/rtc-rv8803.c +++ b/drivers/rtc/rtc-rv8803.c @@ -645,8 +645,7 @@ static int rv8803_probe(struct i2c_client *client) mutex_init(&rv8803->flags_lock); rv8803->client = client; if (client->dev.of_node) { - rv8803->type = (enum rv8803_type) - of_device_get_match_data(&client->dev); + rv8803->type = (uintptr_t)of_device_get_match_data(&client->dev); } else { const struct i2c_device_id *id = i2c_match_id(rv8803_id, client); -- GitLab From 4ebbd463050d14989b4dd2de52deb0779969af41 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 12:39:01 +0200 Subject: [PATCH 1109/3445] rtc: jz4740: fix Wvoid-pointer-to-enum-cast warning 'type' is an enum, thus cast of pointer on 64-bit compile test with W=1 causes: rtc-jz4740.c:352:14: error: cast to smaller integer type 'enum jz4740_rtc_type' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810103902.151145-3-krzysztof.kozlowski@linaro.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-jz4740.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 6ba889d7d4c4f..bafa7d1b9b883 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -349,7 +349,7 @@ static int jz4740_rtc_probe(struct platform_device *pdev) if (!rtc) return -ENOMEM; - rtc->type = (enum jz4740_rtc_type)device_get_match_data(dev); + rtc->type = (uintptr_t)device_get_match_data(dev); irq = platform_get_irq(pdev, 0); if (irq < 0) -- GitLab From e5aabfbc09ca2037e299e0c2c41235922c39b840 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 12:39:02 +0200 Subject: [PATCH 1110/3445] rtc: rs5c372: fix Wvoid-pointer-to-enum-cast warning 'type' is an enum, thus cast of pointer on 64-bit compile test with W=1 causes: rtc-rs5c372.c:829:19: error: cast to smaller integer type 'enum rtc_type' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230810103902.151145-4-krzysztof.kozlowski@linaro.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rs5c372.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index ecabeef091960..f8fab0205f8cc 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -826,8 +826,7 @@ static int rs5c372_probe(struct i2c_client *client) rs5c372->client = client; i2c_set_clientdata(client, rs5c372); if (client->dev.of_node) { - rs5c372->type = (enum rtc_type) - of_device_get_match_data(&client->dev); + rs5c372->type = (uintptr_t)of_device_get_match_data(&client->dev); } else { const struct i2c_device_id *id = i2c_match_id(rs5c372_id, client); rs5c372->type = id->driver_data; -- GitLab From 42f51fb24fd39cc547c086ab3d8a314cc603a91c Mon Sep 17 00:00:00 2001 From: Pavel Kozlov Date: Tue, 15 Aug 2023 19:11:36 +0400 Subject: [PATCH 1111/3445] ARC: atomics: Add compiler barrier to atomic operations... ... to avoid unwanted gcc optimizations SMP kernels fail to boot with commit 596ff4a09b89 ("cpumask: re-introduce constant-sized cpumask optimizations"). | | percpu: BUG: failure at mm/percpu.c:2981/pcpu_build_alloc_info()! | The write operation performed by the SCOND instruction in the atomic inline asm code is not properly passed to the compiler. The compiler cannot correctly optimize a nested loop that runs through the cpumask in the pcpu_build_alloc_info() function. Fix this by add a compiler barrier (memory clobber in inline asm). Apparently atomic ops used to have memory clobber implicitly via surrounding smp_mb(). However commit b64be6836993c431e ("ARC: atomics: implement relaxed variants") removed the smp_mb() for the relaxed variants, but failed to add the explicit compiler barrier. Link: https://github.com/foss-for-synopsys-dwc-arc-processors/linux/issues/135 Cc: # v6.3+ Fixes: b64be6836993c43 ("ARC: atomics: implement relaxed variants") Signed-off-by: Pavel Kozlov Signed-off-by: Vineet Gupta [vgupta: tweaked the changelog and added Fixes tag] --- arch/arc/include/asm/atomic-llsc.h | 6 +++--- arch/arc/include/asm/atomic64-arcv2.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arc/include/asm/atomic-llsc.h b/arch/arc/include/asm/atomic-llsc.h index 1b0ffaeee16d0..5258cb81a16b4 100644 --- a/arch/arc/include/asm/atomic-llsc.h +++ b/arch/arc/include/asm/atomic-llsc.h @@ -18,7 +18,7 @@ static inline void arch_atomic_##op(int i, atomic_t *v) \ : [val] "=&r" (val) /* Early clobber to prevent reg reuse */ \ : [ctr] "r" (&v->counter), /* Not "m": llock only supports reg direct addr mode */ \ [i] "ir" (i) \ - : "cc"); \ + : "cc", "memory"); \ } \ #define ATOMIC_OP_RETURN(op, asm_op) \ @@ -34,7 +34,7 @@ static inline int arch_atomic_##op##_return_relaxed(int i, atomic_t *v) \ : [val] "=&r" (val) \ : [ctr] "r" (&v->counter), \ [i] "ir" (i) \ - : "cc"); \ + : "cc", "memory"); \ \ return val; \ } @@ -56,7 +56,7 @@ static inline int arch_atomic_fetch_##op##_relaxed(int i, atomic_t *v) \ [orig] "=&r" (orig) \ : [ctr] "r" (&v->counter), \ [i] "ir" (i) \ - : "cc"); \ + : "cc", "memory"); \ \ return orig; \ } diff --git a/arch/arc/include/asm/atomic64-arcv2.h b/arch/arc/include/asm/atomic64-arcv2.h index 6b6db981967ae..9b5791b854713 100644 --- a/arch/arc/include/asm/atomic64-arcv2.h +++ b/arch/arc/include/asm/atomic64-arcv2.h @@ -60,7 +60,7 @@ static inline void arch_atomic64_##op(s64 a, atomic64_t *v) \ " bnz 1b \n" \ : "=&r"(val) \ : "r"(&v->counter), "ir"(a) \ - : "cc"); \ + : "cc", "memory"); \ } \ #define ATOMIC64_OP_RETURN(op, op1, op2) \ @@ -77,7 +77,7 @@ static inline s64 arch_atomic64_##op##_return_relaxed(s64 a, atomic64_t *v) \ " bnz 1b \n" \ : [val] "=&r"(val) \ : "r"(&v->counter), "ir"(a) \ - : "cc"); /* memory clobber comes from smp_mb() */ \ + : "cc", "memory"); \ \ return val; \ } @@ -99,7 +99,7 @@ static inline s64 arch_atomic64_fetch_##op##_relaxed(s64 a, atomic64_t *v) \ " bnz 1b \n" \ : "=&r"(orig), "=&r"(val) \ : "r"(&v->counter), "ir"(a) \ - : "cc"); /* memory clobber comes from smp_mb() */ \ + : "cc", "memory"); \ \ return orig; \ } -- GitLab From 077af782e2c333f056cbd713f065bd0009a79a57 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 9 Aug 2023 13:42:31 +0200 Subject: [PATCH 1112/3445] kconfig: port qconf to work with Qt6 in addition to Qt5 Tested with Qt5 5.15 and Qt6 6.4. Note that earlier versions of Qt5 are no longer guaranteed to work. Signed-off-by: Boris Kolpackov Signed-off-by: Masahiro Yamada --- scripts/kconfig/qconf-cfg.sh | 25 +++++++++++++++------- scripts/kconfig/qconf.cc | 40 +++++++++++++++++++++++------------- 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/scripts/kconfig/qconf-cfg.sh b/scripts/kconfig/qconf-cfg.sh index 117f36e568fc5..0e113b0f24557 100755 --- a/scripts/kconfig/qconf-cfg.sh +++ b/scripts/kconfig/qconf-cfg.sh @@ -5,7 +5,8 @@ cflags=$1 libs=$2 bin=$3 -PKG="Qt5Core Qt5Gui Qt5Widgets" +PKG5="Qt5Core Qt5Gui Qt5Widgets" +PKG6="Qt6Core Qt6Gui Qt6Widgets" if [ -z "$(command -v ${HOSTPKG_CONFIG})" ]; then echo >&2 "*" @@ -14,16 +15,26 @@ if [ -z "$(command -v ${HOSTPKG_CONFIG})" ]; then exit 1 fi -if ${HOSTPKG_CONFIG} --exists $PKG; then - ${HOSTPKG_CONFIG} --cflags ${PKG} > ${cflags} - ${HOSTPKG_CONFIG} --libs ${PKG} > ${libs} +if ${HOSTPKG_CONFIG} --exists $PKG6; then + ${HOSTPKG_CONFIG} --cflags ${PKG6} > ${cflags} + # Qt6 requires C++17. + echo -std=c++17 >> ${cflags} + ${HOSTPKG_CONFIG} --libs ${PKG6} > ${libs} + ${HOSTPKG_CONFIG} --variable=libexecdir Qt6Core > ${bin} + exit 0 +fi + +if ${HOSTPKG_CONFIG} --exists $PKG5; then + ${HOSTPKG_CONFIG} --cflags ${PKG5} > ${cflags} + ${HOSTPKG_CONFIG} --libs ${PKG5} > ${libs} ${HOSTPKG_CONFIG} --variable=host_bins Qt5Core > ${bin} exit 0 fi echo >&2 "*" -echo >&2 "* Could not find Qt5 via ${HOSTPKG_CONFIG}." -echo >&2 "* Please install Qt5 and make sure it's in PKG_CONFIG_PATH" -echo >&2 "* You need $PKG" +echo >&2 "* Could not find Qt6 or Qt5 via ${HOSTPKG_CONFIG}." +echo >&2 "* Please install Qt6 or Qt5 and make sure it's in PKG_CONFIG_PATH" +echo >&2 "* You need $PKG6 for Qt6" +echo >&2 "* You need $PKG5 for Qt5" echo >&2 "*" exit 1 diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index 78087b2d9ac67..620a3527c767a 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -5,10 +5,10 @@ */ #include +#include #include #include #include -#include #include #include #include @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -1126,7 +1128,7 @@ QString ConfigInfoView::debug_info(struct symbol *sym) QString ConfigInfoView::print_filter(const QString &str) { - QRegExp re("[<>&\"\\n]"); + QRegularExpression re("[<>&\"\\n]"); QString res = str; for (int i = 0; (i = res.indexOf(re, i)) >= 0;) { switch (res[i].toLatin1()) { @@ -1322,15 +1324,15 @@ ConfigMainWindow::ConfigMainWindow(void) int width, height; char title[256]; - QDesktopWidget *d = configApp->desktop(); snprintf(title, sizeof(title), "%s%s", rootmenu.prompt->text, "" ); setWindowTitle(title); - width = configSettings->value("/window width", d->width() - 64).toInt(); - height = configSettings->value("/window height", d->height() - 64).toInt(); + QRect g = configApp->primaryScreen()->geometry(); + width = configSettings->value("/window width", g.width() - 64).toInt(); + height = configSettings->value("/window height", g.height() - 64).toInt(); resize(width, height); x = configSettings->value("/window x"); y = configSettings->value("/window y"); @@ -1379,17 +1381,17 @@ ConfigMainWindow::ConfigMainWindow(void) this, &ConfigMainWindow::goBack); QAction *quitAction = new QAction("&Quit", this); - quitAction->setShortcut(Qt::CTRL + Qt::Key_Q); + quitAction->setShortcut(Qt::CTRL | Qt::Key_Q); connect(quitAction, &QAction::triggered, this, &ConfigMainWindow::close); QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this); - loadAction->setShortcut(Qt::CTRL + Qt::Key_L); + loadAction->setShortcut(Qt::CTRL | Qt::Key_L); connect(loadAction, &QAction::triggered, this, &ConfigMainWindow::loadConfig); saveAction = new QAction(QPixmap(xpm_save), "&Save", this); - saveAction->setShortcut(Qt::CTRL + Qt::Key_S); + saveAction->setShortcut(Qt::CTRL | Qt::Key_S); connect(saveAction, &QAction::triggered, this, &ConfigMainWindow::saveConfig); @@ -1403,7 +1405,7 @@ ConfigMainWindow::ConfigMainWindow(void) connect(saveAsAction, &QAction::triggered, this, &ConfigMainWindow::saveConfigAs); QAction *searchAction = new QAction("&Find", this); - searchAction->setShortcut(Qt::CTRL + Qt::Key_F); + searchAction->setShortcut(Qt::CTRL | Qt::Key_F); connect(searchAction, &QAction::triggered, this, &ConfigMainWindow::searchConfig); singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this); @@ -1750,11 +1752,21 @@ void ConfigMainWindow::closeEvent(QCloseEvent* e) e->accept(); return; } - QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning, - QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape); - mb.setButtonText(QMessageBox::Yes, "&Save Changes"); - mb.setButtonText(QMessageBox::No, "&Discard Changes"); - mb.setButtonText(QMessageBox::Cancel, "Cancel Exit"); + + QMessageBox mb(QMessageBox::Icon::Warning, "qconf", + "Save configuration?"); + + QPushButton *yb = mb.addButton(QMessageBox::Yes); + QPushButton *db = mb.addButton(QMessageBox::No); + QPushButton *cb = mb.addButton(QMessageBox::Cancel); + + yb->setText("&Save Changes"); + db->setText("&Discard Changes"); + cb->setText("Cancel Exit"); + + mb.setDefaultButton(yb); + mb.setEscapeButton(cb); + switch (mb.exec()) { case QMessageBox::Yes: if (saveConfig()) -- GitLab From 295c95aa7e0310ad8a89e98f1632d066e8526bb2 Mon Sep 17 00:00:00 2001 From: Shiraz Saleem Date: Tue, 15 Aug 2023 19:12:09 -0500 Subject: [PATCH 1113/3445] RDMA/irdma: Drop unused kernel push code The driver has code blocks for kernel push WQEs but does not map the doorbell page rendering this mode non functional [1] Remove code associated with this feature from the kernel fast path as there is currently no plan of record to support this. This also address a sparse issue reported by lkp. drivers/infiniband/hw/irdma/uk.c:285:24: sparse: sparse: incorrect type in assignment (different base types) @@ expected bool [usertype] push_wqe:1 @@ got restricted __le32 [usertype] *push_db @@ drivers/infiniband/hw/irdma/uk.c:285:24: sparse: expected bool [usertype] push_wqe:1 drivers/infiniband/hw/irdma/uk.c:285:24: sparse: got restricted __le32 [usertype] *push_db drivers/infiniband/hw/irdma/uk.c:386:24: sparse: sparse: incorrect type in assignment (different base types) @@ expected bool [usertype] push_wqe:1 @@ got restricted __le32 [usertype] *push_db @@ [1] https://lore.kernel.org/linux-rdma/20230815051809.GB22185@unreal/T/#t Fixes: 272bba19d631 ("RDMA: Remove unnecessary ternary operators") Fixes: 551c46edc769 ("RDMA/irdma: Add user/kernel shared libraries") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202308110251.BV6BcwUR-lkp@intel.com/ Signed-off-by: Shiraz Saleem Link: https://lore.kernel.org/r/20230816001209.1721-1-shiraz.saleem@intel.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/irdma/ctrl.c | 12 +-- drivers/infiniband/hw/irdma/type.h | 1 - drivers/infiniband/hw/irdma/uk.c | 117 ++++------------------------- drivers/infiniband/hw/irdma/user.h | 8 -- 4 files changed, 19 insertions(+), 119 deletions(-) diff --git a/drivers/infiniband/hw/irdma/ctrl.c b/drivers/infiniband/hw/irdma/ctrl.c index b90abdc85057f..b1fdddd2fa1a9 100644 --- a/drivers/infiniband/hw/irdma/ctrl.c +++ b/drivers/infiniband/hw/irdma/ctrl.c @@ -1301,7 +1301,6 @@ int irdma_sc_mr_fast_register(struct irdma_sc_qp *qp, sq_info.wr_id = info->wr_id; sq_info.signaled = info->signaled; - sq_info.push_wqe = info->push_wqe; wqe = irdma_qp_get_next_send_wqe(&qp->qp_uk, &wqe_idx, IRDMA_QP_WQE_MIN_QUANTA, 0, &sq_info); @@ -1335,7 +1334,6 @@ int irdma_sc_mr_fast_register(struct irdma_sc_qp *qp, FIELD_PREP(IRDMAQPSQ_HPAGESIZE, page_size) | FIELD_PREP(IRDMAQPSQ_STAGRIGHTS, info->access_rights) | FIELD_PREP(IRDMAQPSQ_VABASEDTO, info->addr_type) | - FIELD_PREP(IRDMAQPSQ_PUSHWQE, (sq_info.push_wqe ? 1 : 0)) | FIELD_PREP(IRDMAQPSQ_READFENCE, info->read_fence) | FIELD_PREP(IRDMAQPSQ_LOCALFENCE, info->local_fence) | FIELD_PREP(IRDMAQPSQ_SIGCOMPL, info->signaled) | @@ -1346,13 +1344,9 @@ int irdma_sc_mr_fast_register(struct irdma_sc_qp *qp, print_hex_dump_debug("WQE: FAST_REG WQE", DUMP_PREFIX_OFFSET, 16, 8, wqe, IRDMA_QP_WQE_MIN_SIZE, false); - if (sq_info.push_wqe) { - irdma_qp_push_wqe(&qp->qp_uk, wqe, IRDMA_QP_WQE_MIN_QUANTA, - wqe_idx, post_sq); - } else { - if (post_sq) - irdma_uk_qp_post_wr(&qp->qp_uk); - } + + if (post_sq) + irdma_uk_qp_post_wr(&qp->qp_uk); return 0; } diff --git a/drivers/infiniband/hw/irdma/type.h b/drivers/infiniband/hw/irdma/type.h index 5ee68604e59fc..b49a98c208bf6 100644 --- a/drivers/infiniband/hw/irdma/type.h +++ b/drivers/infiniband/hw/irdma/type.h @@ -1015,7 +1015,6 @@ struct irdma_fast_reg_stag_info { bool local_fence:1; bool read_fence:1; bool signaled:1; - bool push_wqe:1; bool use_hmc_fcn_index:1; u8 hmc_fcn_index; bool use_pf_rid:1; diff --git a/drivers/infiniband/hw/irdma/uk.c b/drivers/infiniband/hw/irdma/uk.c index 6f9238c4fe20d..9f84d997e3abf 100644 --- a/drivers/infiniband/hw/irdma/uk.c +++ b/drivers/infiniband/hw/irdma/uk.c @@ -127,10 +127,7 @@ void irdma_uk_qp_post_wr(struct irdma_qp_uk *qp) hw_sq_tail = (u32)FIELD_GET(IRDMA_QP_DBSA_HW_SQ_TAIL, temp); sw_sq_head = IRDMA_RING_CURRENT_HEAD(qp->sq_ring); if (sw_sq_head != qp->initial_ring.head) { - if (qp->push_dropped) { - writel(qp->qp_id, qp->wqe_alloc_db); - qp->push_dropped = false; - } else if (sw_sq_head != hw_sq_tail) { + if (sw_sq_head != hw_sq_tail) { if (sw_sq_head > qp->initial_ring.head) { if (hw_sq_tail >= qp->initial_ring.head && hw_sq_tail < sw_sq_head) @@ -146,38 +143,6 @@ void irdma_uk_qp_post_wr(struct irdma_qp_uk *qp) qp->initial_ring.head = qp->sq_ring.head; } -/** - * irdma_qp_ring_push_db - ring qp doorbell - * @qp: hw qp ptr - * @wqe_idx: wqe index - */ -static void irdma_qp_ring_push_db(struct irdma_qp_uk *qp, u32 wqe_idx) -{ - set_32bit_val(qp->push_db, 0, - FIELD_PREP(IRDMA_WQEALLOC_WQE_DESC_INDEX, wqe_idx >> 3) | qp->qp_id); - qp->initial_ring.head = qp->sq_ring.head; - qp->push_mode = true; - qp->push_dropped = false; -} - -void irdma_qp_push_wqe(struct irdma_qp_uk *qp, __le64 *wqe, u16 quanta, - u32 wqe_idx, bool post_sq) -{ - __le64 *push; - - if (IRDMA_RING_CURRENT_HEAD(qp->initial_ring) != - IRDMA_RING_CURRENT_TAIL(qp->sq_ring) && - !qp->push_mode) { - if (post_sq) - irdma_uk_qp_post_wr(qp); - } else { - push = (__le64 *)((uintptr_t)qp->push_wqe + - (wqe_idx & 0x7) * 0x20); - memcpy(push, wqe, quanta * IRDMA_QP_WQE_MIN_SIZE); - irdma_qp_ring_push_db(qp, wqe_idx); - } -} - /** * irdma_qp_get_next_send_wqe - pad with NOP if needed, return where next WR should go * @qp: hw qp ptr @@ -192,7 +157,6 @@ __le64 *irdma_qp_get_next_send_wqe(struct irdma_qp_uk *qp, u32 *wqe_idx, { __le64 *wqe; __le64 *wqe_0 = NULL; - u32 nop_wqe_idx; u16 avail_quanta; u16 i; @@ -209,14 +173,10 @@ __le64 *irdma_qp_get_next_send_wqe(struct irdma_qp_uk *qp, u32 *wqe_idx, IRDMA_SQ_RING_FREE_QUANTA(qp->sq_ring)) return NULL; - nop_wqe_idx = IRDMA_RING_CURRENT_HEAD(qp->sq_ring); for (i = 0; i < avail_quanta; i++) { irdma_nop_1(qp); IRDMA_RING_MOVE_HEAD_NOCHECK(qp->sq_ring); } - if (qp->push_db && info->push_wqe) - irdma_qp_push_wqe(qp, qp->sq_base[nop_wqe_idx].elem, - avail_quanta, nop_wqe_idx, true); } *wqe_idx = IRDMA_RING_CURRENT_HEAD(qp->sq_ring); @@ -282,8 +242,6 @@ int irdma_uk_rdma_write(struct irdma_qp_uk *qp, struct irdma_post_sq_info *info, bool read_fence = false; u16 quanta; - info->push_wqe = qp->push_db; - op_info = &info->op.rdma_write; if (op_info->num_lo_sges > qp->max_sq_frag_cnt) return -EINVAL; @@ -344,7 +302,6 @@ int irdma_uk_rdma_write(struct irdma_qp_uk *qp, struct irdma_post_sq_info *info, FIELD_PREP(IRDMAQPSQ_IMMDATAFLAG, info->imm_data_valid) | FIELD_PREP(IRDMAQPSQ_REPORTRTT, info->report_rtt) | FIELD_PREP(IRDMAQPSQ_ADDFRAGCNT, addl_frag_cnt) | - FIELD_PREP(IRDMAQPSQ_PUSHWQE, info->push_wqe) | FIELD_PREP(IRDMAQPSQ_READFENCE, read_fence) | FIELD_PREP(IRDMAQPSQ_LOCALFENCE, info->local_fence) | FIELD_PREP(IRDMAQPSQ_SIGCOMPL, info->signaled) | @@ -353,12 +310,9 @@ int irdma_uk_rdma_write(struct irdma_qp_uk *qp, struct irdma_post_sq_info *info, dma_wmb(); /* make sure WQE is populated before valid bit is set */ set_64bit_val(wqe, 24, hdr); - if (info->push_wqe) { - irdma_qp_push_wqe(qp, wqe, quanta, wqe_idx, post_sq); - } else { - if (post_sq) - irdma_uk_qp_post_wr(qp); - } + + if (post_sq) + irdma_uk_qp_post_wr(qp); return 0; } @@ -383,8 +337,6 @@ int irdma_uk_rdma_read(struct irdma_qp_uk *qp, struct irdma_post_sq_info *info, u16 quanta; u64 hdr; - info->push_wqe = qp->push_db; - op_info = &info->op.rdma_read; if (qp->max_sq_frag_cnt < op_info->num_lo_sges) return -EINVAL; @@ -431,7 +383,6 @@ int irdma_uk_rdma_read(struct irdma_qp_uk *qp, struct irdma_post_sq_info *info, FIELD_PREP(IRDMAQPSQ_ADDFRAGCNT, addl_frag_cnt) | FIELD_PREP(IRDMAQPSQ_OPCODE, (inv_stag ? IRDMAQP_OP_RDMA_READ_LOC_INV : IRDMAQP_OP_RDMA_READ)) | - FIELD_PREP(IRDMAQPSQ_PUSHWQE, info->push_wqe) | FIELD_PREP(IRDMAQPSQ_READFENCE, info->read_fence) | FIELD_PREP(IRDMAQPSQ_LOCALFENCE, local_fence) | FIELD_PREP(IRDMAQPSQ_SIGCOMPL, info->signaled) | @@ -440,12 +391,9 @@ int irdma_uk_rdma_read(struct irdma_qp_uk *qp, struct irdma_post_sq_info *info, dma_wmb(); /* make sure WQE is populated before valid bit is set */ set_64bit_val(wqe, 24, hdr); - if (info->push_wqe) { - irdma_qp_push_wqe(qp, wqe, quanta, wqe_idx, post_sq); - } else { - if (post_sq) - irdma_uk_qp_post_wr(qp); - } + + if (post_sq) + irdma_uk_qp_post_wr(qp); return 0; } @@ -468,8 +416,6 @@ int irdma_uk_send(struct irdma_qp_uk *qp, struct irdma_post_sq_info *info, bool read_fence = false; u16 quanta; - info->push_wqe = qp->push_db; - op_info = &info->op.send; if (qp->max_sq_frag_cnt < op_info->num_sges) return -EINVAL; @@ -530,7 +476,6 @@ int irdma_uk_send(struct irdma_qp_uk *qp, struct irdma_post_sq_info *info, FIELD_PREP(IRDMAQPSQ_REPORTRTT, (info->report_rtt ? 1 : 0)) | FIELD_PREP(IRDMAQPSQ_OPCODE, info->op_type) | FIELD_PREP(IRDMAQPSQ_ADDFRAGCNT, addl_frag_cnt) | - FIELD_PREP(IRDMAQPSQ_PUSHWQE, info->push_wqe) | FIELD_PREP(IRDMAQPSQ_READFENCE, read_fence) | FIELD_PREP(IRDMAQPSQ_LOCALFENCE, info->local_fence) | FIELD_PREP(IRDMAQPSQ_SIGCOMPL, info->signaled) | @@ -541,12 +486,9 @@ int irdma_uk_send(struct irdma_qp_uk *qp, struct irdma_post_sq_info *info, dma_wmb(); /* make sure WQE is populated before valid bit is set */ set_64bit_val(wqe, 24, hdr); - if (info->push_wqe) { - irdma_qp_push_wqe(qp, wqe, quanta, wqe_idx, post_sq); - } else { - if (post_sq) - irdma_uk_qp_post_wr(qp); - } + + if (post_sq) + irdma_uk_qp_post_wr(qp); return 0; } @@ -720,7 +662,6 @@ int irdma_uk_inline_rdma_write(struct irdma_qp_uk *qp, u32 i, total_size = 0; u16 quanta; - info->push_wqe = qp->push_db; op_info = &info->op.rdma_write; if (unlikely(qp->max_sq_frag_cnt < op_info->num_lo_sges)) @@ -750,7 +691,6 @@ int irdma_uk_inline_rdma_write(struct irdma_qp_uk *qp, FIELD_PREP(IRDMAQPSQ_REPORTRTT, info->report_rtt ? 1 : 0) | FIELD_PREP(IRDMAQPSQ_INLINEDATAFLAG, 1) | FIELD_PREP(IRDMAQPSQ_IMMDATAFLAG, info->imm_data_valid ? 1 : 0) | - FIELD_PREP(IRDMAQPSQ_PUSHWQE, info->push_wqe ? 1 : 0) | FIELD_PREP(IRDMAQPSQ_READFENCE, read_fence) | FIELD_PREP(IRDMAQPSQ_LOCALFENCE, info->local_fence) | FIELD_PREP(IRDMAQPSQ_SIGCOMPL, info->signaled) | @@ -767,12 +707,8 @@ int irdma_uk_inline_rdma_write(struct irdma_qp_uk *qp, set_64bit_val(wqe, 24, hdr); - if (info->push_wqe) { - irdma_qp_push_wqe(qp, wqe, quanta, wqe_idx, post_sq); - } else { - if (post_sq) - irdma_uk_qp_post_wr(qp); - } + if (post_sq) + irdma_uk_qp_post_wr(qp); return 0; } @@ -794,7 +730,6 @@ int irdma_uk_inline_send(struct irdma_qp_uk *qp, u32 i, total_size = 0; u16 quanta; - info->push_wqe = qp->push_db; op_info = &info->op.send; if (unlikely(qp->max_sq_frag_cnt < op_info->num_sges)) @@ -827,7 +762,6 @@ int irdma_uk_inline_send(struct irdma_qp_uk *qp, (info->imm_data_valid ? 1 : 0)) | FIELD_PREP(IRDMAQPSQ_REPORTRTT, (info->report_rtt ? 1 : 0)) | FIELD_PREP(IRDMAQPSQ_INLINEDATAFLAG, 1) | - FIELD_PREP(IRDMAQPSQ_PUSHWQE, info->push_wqe) | FIELD_PREP(IRDMAQPSQ_READFENCE, read_fence) | FIELD_PREP(IRDMAQPSQ_LOCALFENCE, info->local_fence) | FIELD_PREP(IRDMAQPSQ_SIGCOMPL, info->signaled) | @@ -845,12 +779,8 @@ int irdma_uk_inline_send(struct irdma_qp_uk *qp, set_64bit_val(wqe, 24, hdr); - if (info->push_wqe) { - irdma_qp_push_wqe(qp, wqe, quanta, wqe_idx, post_sq); - } else { - if (post_sq) - irdma_uk_qp_post_wr(qp); - } + if (post_sq) + irdma_uk_qp_post_wr(qp); return 0; } @@ -872,7 +802,6 @@ int irdma_uk_stag_local_invalidate(struct irdma_qp_uk *qp, bool local_fence = false; struct ib_sge sge = {}; - info->push_wqe = qp->push_db; op_info = &info->op.inv_local_stag; local_fence = info->local_fence; @@ -889,7 +818,6 @@ int irdma_uk_stag_local_invalidate(struct irdma_qp_uk *qp, set_64bit_val(wqe, 16, 0); hdr = FIELD_PREP(IRDMAQPSQ_OPCODE, IRDMA_OP_TYPE_INV_STAG) | - FIELD_PREP(IRDMAQPSQ_PUSHWQE, info->push_wqe) | FIELD_PREP(IRDMAQPSQ_READFENCE, info->read_fence) | FIELD_PREP(IRDMAQPSQ_LOCALFENCE, local_fence) | FIELD_PREP(IRDMAQPSQ_SIGCOMPL, info->signaled) | @@ -899,13 +827,8 @@ int irdma_uk_stag_local_invalidate(struct irdma_qp_uk *qp, set_64bit_val(wqe, 24, hdr); - if (info->push_wqe) { - irdma_qp_push_wqe(qp, wqe, IRDMA_QP_WQE_MIN_QUANTA, wqe_idx, - post_sq); - } else { - if (post_sq) - irdma_uk_qp_post_wr(qp); - } + if (post_sq) + irdma_uk_qp_post_wr(qp); return 0; } @@ -1124,7 +1047,6 @@ int irdma_uk_cq_poll_cmpl(struct irdma_cq_uk *cq, info->q_type = (u8)FIELD_GET(IRDMA_CQ_SQ, qword3); info->error = (bool)FIELD_GET(IRDMA_CQ_ERROR, qword3); - info->push_dropped = (bool)FIELD_GET(IRDMACQ_PSHDROP, qword3); info->ipv4 = (bool)FIELD_GET(IRDMACQ_IPV4, qword3); if (info->error) { info->major_err = FIELD_GET(IRDMA_CQ_MAJERR, qword3); @@ -1213,11 +1135,6 @@ int irdma_uk_cq_poll_cmpl(struct irdma_cq_uk *cq, return irdma_uk_cq_poll_cmpl(cq, info); } } - /*cease posting push mode on push drop*/ - if (info->push_dropped) { - qp->push_mode = false; - qp->push_dropped = true; - } if (info->comp_status != IRDMA_COMPL_STATUS_FLUSHED) { info->wr_id = qp->sq_wrtrk_array[wqe_idx].wrid; if (!info->comp_status) @@ -1521,7 +1438,6 @@ int irdma_uk_qp_init(struct irdma_qp_uk *qp, struct irdma_qp_uk_init_info *info) qp->wqe_alloc_db = info->wqe_alloc_db; qp->qp_id = info->qp_id; qp->sq_size = info->sq_size; - qp->push_mode = false; qp->max_sq_frag_cnt = info->max_sq_frag_cnt; sq_ring_size = qp->sq_size << info->sq_shift; IRDMA_RING_INIT(qp->sq_ring, sq_ring_size); @@ -1616,7 +1532,6 @@ int irdma_nop(struct irdma_qp_uk *qp, u64 wr_id, bool signaled, bool post_sq) u32 wqe_idx; struct irdma_post_sq_info info = {}; - info.push_wqe = false; info.wr_id = wr_id; wqe = irdma_qp_get_next_send_wqe(qp, &wqe_idx, IRDMA_QP_WQE_MIN_QUANTA, 0, &info); diff --git a/drivers/infiniband/hw/irdma/user.h b/drivers/infiniband/hw/irdma/user.h index dd145ec72a915..36feca57b274b 100644 --- a/drivers/infiniband/hw/irdma/user.h +++ b/drivers/infiniband/hw/irdma/user.h @@ -216,7 +216,6 @@ struct irdma_post_sq_info { bool local_fence:1; bool inline_data:1; bool imm_data_valid:1; - bool push_wqe:1; bool report_rtt:1; bool udp_hdr:1; bool defer_flag:1; @@ -248,7 +247,6 @@ struct irdma_cq_poll_info { u8 op_type; u8 q_type; bool stag_invalid_set:1; /* or L_R_Key set */ - bool push_dropped:1; bool error:1; bool solicited_event:1; bool ipv4:1; @@ -321,8 +319,6 @@ struct irdma_qp_uk { struct irdma_sq_uk_wr_trk_info *sq_wrtrk_array; u64 *rq_wrid_array; __le64 *shadow_area; - __le32 *push_db; - __le64 *push_wqe; struct irdma_ring sq_ring; struct irdma_ring rq_ring; struct irdma_ring initial_ring; @@ -342,8 +338,6 @@ struct irdma_qp_uk { u8 rq_wqe_size; u8 rq_wqe_size_multiplier; bool deferred_flag:1; - bool push_mode:1; /* whether the last post wqe was pushed */ - bool push_dropped:1; bool first_sq_wq:1; bool sq_flush_complete:1; /* Indicates flush was seen and SQ was empty after the flush */ bool rq_flush_complete:1; /* Indicates flush was seen and RQ was empty after the flush */ @@ -415,7 +409,5 @@ int irdma_get_sqdepth(struct irdma_uk_attrs *uk_attrs, u32 sq_size, u8 shift, u32 *wqdepth); int irdma_get_rqdepth(struct irdma_uk_attrs *uk_attrs, u32 rq_size, u8 shift, u32 *wqdepth); -void irdma_qp_push_wqe(struct irdma_qp_uk *qp, __le64 *wqe, u16 quanta, - u32 wqe_idx, bool post_sq); void irdma_clr_wqes(struct irdma_qp_uk *qp, u32 qp_wqe_idx); #endif /* IRDMA_USER_H */ -- GitLab From 18ddaeb03bdb65b84fece11a8cac5bf583ae1b91 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 15 Aug 2023 14:39:53 -0600 Subject: [PATCH 1114/3445] RDMA/mlx4: Copy union directly Copy union directly instead of using memcpy(). Note that in this case, a direct assignment is more readable and consistent with the subsequent assignments. This addresses the following -Wstringop-overflow warning seen in s390 with defconfig: drivers/infiniband/hw/mlx4/main.c:296:33: warning: writing 16 bytes into a region of size 0 [-Wstringop-overflow=] 296 | memcpy(&port_gid_table->gids[free].gid, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 297 | &attr->gid, sizeof(attr->gid)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This helps with the ongoing efforts to globally enable -Wstringop-overflow. Link: https://github.com/KSPP/linux/issues/308 Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/ZNvimeRAPkJ24zRG@work Reviewed-by: Kees Cook Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/mlx4/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 216aacd72e4fc..2d2cd17e02e65 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -293,8 +293,7 @@ static int mlx4_ib_add_gid(const struct ib_gid_attr *attr, void **context) ret = -ENOMEM; } else { *context = port_gid_table->gids[free].ctx; - memcpy(&port_gid_table->gids[free].gid, - &attr->gid, sizeof(attr->gid)); + port_gid_table->gids[free].gid = attr->gid; port_gid_table->gids[free].gid_type = attr->gid_type; port_gid_table->gids[free].vlan_id = vlan_id; port_gid_table->gids[free].ctx->real_index = free; -- GitLab From b8bd342d50cbf606666488488f9fea374aceb2d5 Mon Sep 17 00:00:00 2001 From: ruanmeisi Date: Tue, 25 Apr 2023 19:13:54 +0800 Subject: [PATCH 1115/3445] fuse: nlookup missing decrement in fuse_direntplus_link During our debugging of glusterfs, we found an Assertion failed error: inode_lookup >= nlookup, which was caused by the nlookup value in the kernel being greater than that in the FUSE file system. The issue was introduced by fuse_direntplus_link, where in the function, fuse_iget increments nlookup, and if d_splice_alias returns failure, fuse_direntplus_link returns failure without decrementing nlookup https://github.com/gluster/glusterfs/pull/4081 Signed-off-by: ruanmeisi Fixes: 0b05b18381ee ("fuse: implement NFS-like readdirplus support") Cc: # v3.9 Signed-off-by: Miklos Szeredi --- fs/fuse/readdir.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c index dc603479b30ef..b3d498163f973 100644 --- a/fs/fuse/readdir.c +++ b/fs/fuse/readdir.c @@ -243,8 +243,16 @@ retry: dput(dentry); dentry = alias; } - if (IS_ERR(dentry)) + if (IS_ERR(dentry)) { + if (!IS_ERR(inode)) { + struct fuse_inode *fi = get_fuse_inode(inode); + + spin_lock(&fi->lock); + fi->nlookup--; + spin_unlock(&fi->lock); + } return PTR_ERR(dentry); + } } if (fc->readdirplus_auto) set_bit(FUSE_I_INIT_RDPLUS, &get_fuse_inode(inode)->state); -- GitLab From cbd8c5aae2a988bafd4586bea710eeddc30a82ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= Date: Thu, 6 Jul 2023 11:37:32 -0400 Subject: [PATCH 1116/3445] thermal/drivers/mediatek/lvts_thermal: Handle IRQ on all controllers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a single IRQ handler for each LVTS thermal domain, and it is supposed to check each of its underlying controllers for the origin of the interrupt and clear its status. However due to a typo, only the first controller was ever being handled, which resulted in the interrupt never being cleared when it happened on the other controllers. Add the missing index so interrupts are handled for all controllers. Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver") Reviewed-by: Matthias Brugger Reviewed-by: AngeloGioacchino Del Regno Tested-by: Chen-Yu Tsai Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: Alexandre Mergnat Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230706153823.201943-2-nfraprado@collabora.com --- drivers/thermal/mediatek/lvts_thermal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c index 054c965ae5e11..4ec09cb8f6677 100644 --- a/drivers/thermal/mediatek/lvts_thermal.c +++ b/drivers/thermal/mediatek/lvts_thermal.c @@ -451,7 +451,7 @@ static irqreturn_t lvts_irq_handler(int irq, void *data) for (i = 0; i < lvts_td->num_lvts_ctrl; i++) { - aux = lvts_ctrl_irq_handler(lvts_td->lvts_ctrl); + aux = lvts_ctrl_irq_handler(&lvts_td->lvts_ctrl[i]); if (aux != IRQ_HANDLED) continue; -- GitLab From 64de162e34e4cb2982a1d96e492f018026a61c1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= Date: Thu, 6 Jul 2023 11:37:33 -0400 Subject: [PATCH 1117/3445] thermal/drivers/mediatek/lvts_thermal: Honor sensors in immediate mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each controller can be configured to operate on immediate or filtered mode. On filtered mode, the sensors are enabled by setting the corresponding bits in MONCTL0, while on immediate mode, by setting MSRCTL1. Previously, the code would set MSRCTL1 for all four sensors when configured to immediate mode, but given that the controller might not have all four sensors connected, this would cause interrupts to trigger for non-existent sensors. Fix this by handling the MSRCTL1 register analogously to the MONCTL0: only enable the sensors that were declared. Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver") Reviewed-by: AngeloGioacchino Del Regno Tested-by: Chen-Yu Tsai Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: Alexandre Mergnat Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230706153823.201943-3-nfraprado@collabora.com --- drivers/thermal/mediatek/lvts_thermal.c | 57 ++++++++++++++----------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c index 4ec09cb8f6677..92f4784bb98cd 100644 --- a/drivers/thermal/mediatek/lvts_thermal.c +++ b/drivers/thermal/mediatek/lvts_thermal.c @@ -896,24 +896,6 @@ static int lvts_ctrl_configure(struct device *dev, struct lvts_ctrl *lvts_ctrl) LVTS_HW_FILTER << 3 | LVTS_HW_FILTER; writel(value, LVTS_MSRCTL0(lvts_ctrl->base)); - /* - * LVTS_MSRCTL1 : Measurement control - * - * Bits: - * - * 9: Ignore MSRCTL0 config and do immediate measurement on sensor3 - * 6: Ignore MSRCTL0 config and do immediate measurement on sensor2 - * 5: Ignore MSRCTL0 config and do immediate measurement on sensor1 - * 4: Ignore MSRCTL0 config and do immediate measurement on sensor0 - * - * That configuration will ignore the filtering and the delays - * introduced below in MONCTL1 and MONCTL2 - */ - if (lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE) { - value = BIT(9) | BIT(6) | BIT(5) | BIT(4); - writel(value, LVTS_MSRCTL1(lvts_ctrl->base)); - } - /* * LVTS_MONCTL1 : Period unit and group interval configuration * @@ -979,6 +961,15 @@ static int lvts_ctrl_start(struct device *dev, struct lvts_ctrl *lvts_ctrl) struct thermal_zone_device *tz; u32 sensor_map = 0; int i; + /* + * Bitmaps to enable each sensor on immediate and filtered modes, as + * described in MSRCTL1 and MONCTL0 registers below, respectively. + */ + u32 sensor_imm_bitmap[] = { BIT(4), BIT(5), BIT(6), BIT(9) }; + u32 sensor_filt_bitmap[] = { BIT(0), BIT(1), BIT(2), BIT(3) }; + + u32 *sensor_bitmap = lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE ? + sensor_imm_bitmap : sensor_filt_bitmap; for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++) { @@ -1016,20 +1007,38 @@ static int lvts_ctrl_start(struct device *dev, struct lvts_ctrl *lvts_ctrl) * map, so we can enable the temperature monitoring in * the hardware thermal controller. */ - sensor_map |= BIT(i); + sensor_map |= sensor_bitmap[i]; } /* - * Bits: - * 9: Single point access flow - * 0-3: Enable sensing point 0-3 - * * The initialization of the thermal zones give us * which sensor point to enable. If any thermal zone * was not described in the device tree, it won't be * enabled here in the sensor map. */ - writel(sensor_map | BIT(9), LVTS_MONCTL0(lvts_ctrl->base)); + if (lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE) { + /* + * LVTS_MSRCTL1 : Measurement control + * + * Bits: + * + * 9: Ignore MSRCTL0 config and do immediate measurement on sensor3 + * 6: Ignore MSRCTL0 config and do immediate measurement on sensor2 + * 5: Ignore MSRCTL0 config and do immediate measurement on sensor1 + * 4: Ignore MSRCTL0 config and do immediate measurement on sensor0 + * + * That configuration will ignore the filtering and the delays + * introduced in MONCTL1 and MONCTL2 + */ + writel(sensor_map, LVTS_MSRCTL1(lvts_ctrl->base)); + } else { + /* + * Bits: + * 9: Single point access flow + * 0-3: Enable sensing point 0-3 + */ + writel(sensor_map | BIT(9), LVTS_MONCTL0(lvts_ctrl->base)); + } return 0; } -- GitLab From f79e996c7ed27bb196facbcd1c69ee33631d7051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= Date: Thu, 6 Jul 2023 11:37:34 -0400 Subject: [PATCH 1118/3445] thermal/drivers/mediatek/lvts_thermal: Use offset threshold for IRQ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are two kinds of temperature monitoring interrupts available: * High Offset, Low Offset * Hot, Hot to normal, Cold The code currently uses the hot/h2n/cold interrupts, however in a way that doesn't work: the cold threshold is left uninitialized, which prevents the other thresholds from ever triggering, and the h2n interrupt is used as the lower threshold, which prevents the hot interrupt from triggering again after the thresholds are updated by the thermal framework, since a hot interrupt can only trigger again after the hot to normal interrupt has been triggered. But better yet than addressing those issues, is to use the high/low offset interrupts instead. This way only two thresholds need to be managed, which have a simpler state machine, making them a better match to the thermal framework's high and low thresholds. Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver") Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: Alexandre Mergnat Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230706153823.201943-4-nfraprado@collabora.com --- drivers/thermal/mediatek/lvts_thermal.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c index 92f4784bb98cd..978316a45060c 100644 --- a/drivers/thermal/mediatek/lvts_thermal.c +++ b/drivers/thermal/mediatek/lvts_thermal.c @@ -298,9 +298,9 @@ static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high) u32 raw_high = lvts_temp_to_raw(high); /* - * Hot to normal temperature threshold + * Low offset temperature threshold * - * LVTS_H2NTHRE + * LVTS_OFFSETL * * Bits: * @@ -309,13 +309,13 @@ static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high) if (low != -INT_MAX) { pr_debug("%s: Setting low limit temperature interrupt: %d\n", thermal_zone_device_type(tz), low); - writel(raw_low, LVTS_H2NTHRE(base)); + writel(raw_low, LVTS_OFFSETL(base)); } /* - * Hot temperature threshold + * High offset temperature threshold * - * LVTS_HTHRE + * LVTS_OFFSETH * * Bits: * @@ -323,7 +323,7 @@ static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high) */ pr_debug("%s: Setting high limit temperature interrupt: %d\n", thermal_zone_device_type(tz), high); - writel(raw_high, LVTS_HTHRE(base)); + writel(raw_high, LVTS_OFFSETH(base)); return 0; } -- GitLab From 487bf099e85b724c824f5fafaf93c6749c4d2120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= Date: Thu, 6 Jul 2023 11:37:35 -0400 Subject: [PATCH 1119/3445] thermal/drivers/mediatek/lvts_thermal: Disable undesired interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Out of the many interrupts supported by the hardware, the only ones of interest to the driver currently are: * The temperature went over the high offset threshold, for any of the sensors * The temperature went below the low offset threshold, for any of the sensors * The temperature went over the stage3 threshold These are the only thresholds configured by the driver through the OFFSETH, OFFSETL, and PROTTC registers, respectively. The current interrupt mask in LVTS_MONINT_CONF, enables many more interrupts, including data ready on sensors for both filtered and immediate mode. These are not only not handled by the driver, but they are also triggered too often, causing unneeded overhead. Disable these unnecessary interrupts. The meaning of each bit can be seen in the comment describing LVTS_MONINTST in the IRQ handler. Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver") Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Alexandre Mergnat Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230706153823.201943-5-nfraprado@collabora.com --- drivers/thermal/mediatek/lvts_thermal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c index 978316a45060c..72c848f9de4c9 100644 --- a/drivers/thermal/mediatek/lvts_thermal.c +++ b/drivers/thermal/mediatek/lvts_thermal.c @@ -65,7 +65,7 @@ #define LVTS_HW_FILTER 0x2 #define LVTS_TSSEL_CONF 0x13121110 #define LVTS_CALSCALE_CONF 0x300 -#define LVTS_MONINT_CONF 0x9FBF7BDE +#define LVTS_MONINT_CONF 0x8300318C #define LVTS_INT_SENSOR0 0x0009001F #define LVTS_INT_SENSOR1 0x001203E0 -- GitLab From 77354eaef8218bc40d6b37e783b0b8dcca22a7d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= Date: Thu, 6 Jul 2023 11:37:36 -0400 Subject: [PATCH 1120/3445] thermal/drivers/mediatek/lvts_thermal: Don't leave threshold zeroed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The thermal framework might leave the low threshold unset if there aren't any lower trip points. This leaves the register zeroed, which translates to a very high temperature for the low threshold. The interrupt for this threshold is then immediately triggered, and the state machine gets stuck, preventing any other temperature monitoring interrupts to ever trigger. (The same happens by not setting the Cold or Hot to Normal thresholds when using those) Set the unused threshold to a valid low value. This value was chosen so that for any valid golden temperature read from the efuse, when the value is converted to raw and back again to milliCelsius, the result doesn't underflow. Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver") Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: Alexandre Mergnat Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230706153823.201943-6-nfraprado@collabora.com --- drivers/thermal/mediatek/lvts_thermal.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c index 72c848f9de4c9..1ad93a778c9da 100644 --- a/drivers/thermal/mediatek/lvts_thermal.c +++ b/drivers/thermal/mediatek/lvts_thermal.c @@ -83,6 +83,8 @@ #define LVTS_HW_SHUTDOWN_MT8195 105000 +#define LVTS_MINIMUM_THRESHOLD 20000 + static int golden_temp = LVTS_GOLDEN_TEMP_DEFAULT; static int coeff_b = LVTS_COEFF_B; @@ -294,7 +296,7 @@ static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high) { struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz); void __iomem *base = lvts_sensor->base; - u32 raw_low = lvts_temp_to_raw(low); + u32 raw_low = lvts_temp_to_raw(low != -INT_MAX ? low : LVTS_MINIMUM_THRESHOLD); u32 raw_high = lvts_temp_to_raw(high); /* @@ -306,11 +308,9 @@ static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high) * * 14-0 : Raw temperature for threshold */ - if (low != -INT_MAX) { - pr_debug("%s: Setting low limit temperature interrupt: %d\n", - thermal_zone_device_type(tz), low); - writel(raw_low, LVTS_OFFSETL(base)); - } + pr_debug("%s: Setting low limit temperature interrupt: %d\n", + thermal_zone_device_type(tz), low); + writel(raw_low, LVTS_OFFSETL(base)); /* * High offset temperature threshold -- GitLab From 2bba1acf7a4cbe62abbb4c686e0414209ec5943b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= Date: Thu, 6 Jul 2023 11:37:37 -0400 Subject: [PATCH 1121/3445] thermal/drivers/mediatek/lvts_thermal: Manage threshold between sensors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each LVTS thermal controller can have up to four sensors, each capable of triggering its own interrupt when its measured temperature crosses the configured threshold. The threshold for each sensor is handled separately by the thermal framework, since each one is registered with its own thermal zone and trips. However, the temperature thresholds are configured on the controller, and therefore are shared between all sensors on that controller. When the temperature measured by the sensors is different enough to cause the thermal framework to configure different thresholds for each one, interrupts start triggering on sensors outside the last threshold configured. To address the issue, track the thresholds required by each sensor and only actually set the highest one in the hardware, and disable interrupts for all sensors outside the current configured range. Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver") Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: Alexandre Mergnat Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230706153823.201943-7-nfraprado@collabora.com --- drivers/thermal/mediatek/lvts_thermal.c | 69 +++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c index 1ad93a778c9da..61c3de44c40ba 100644 --- a/drivers/thermal/mediatek/lvts_thermal.c +++ b/drivers/thermal/mediatek/lvts_thermal.c @@ -67,6 +67,11 @@ #define LVTS_CALSCALE_CONF 0x300 #define LVTS_MONINT_CONF 0x8300318C +#define LVTS_MONINT_OFFSET_SENSOR0 0xC +#define LVTS_MONINT_OFFSET_SENSOR1 0x180 +#define LVTS_MONINT_OFFSET_SENSOR2 0x3000 +#define LVTS_MONINT_OFFSET_SENSOR3 0x3000000 + #define LVTS_INT_SENSOR0 0x0009001F #define LVTS_INT_SENSOR1 0x001203E0 #define LVTS_INT_SENSOR2 0x00247C00 @@ -112,6 +117,8 @@ struct lvts_sensor { void __iomem *base; int id; int dt_id; + int low_thresh; + int high_thresh; }; struct lvts_ctrl { @@ -121,6 +128,8 @@ struct lvts_ctrl { int num_lvts_sensor; int mode; void __iomem *base; + int low_thresh; + int high_thresh; }; struct lvts_domain { @@ -292,12 +301,66 @@ static int lvts_get_temp(struct thermal_zone_device *tz, int *temp) return 0; } +static void lvts_update_irq_mask(struct lvts_ctrl *lvts_ctrl) +{ + u32 masks[] = { + LVTS_MONINT_OFFSET_SENSOR0, + LVTS_MONINT_OFFSET_SENSOR1, + LVTS_MONINT_OFFSET_SENSOR2, + LVTS_MONINT_OFFSET_SENSOR3, + }; + u32 value = 0; + int i; + + value = readl(LVTS_MONINT(lvts_ctrl->base)); + + for (i = 0; i < ARRAY_SIZE(masks); i++) { + if (lvts_ctrl->sensors[i].high_thresh == lvts_ctrl->high_thresh + && lvts_ctrl->sensors[i].low_thresh == lvts_ctrl->low_thresh) + value |= masks[i]; + else + value &= ~masks[i]; + } + + writel(value, LVTS_MONINT(lvts_ctrl->base)); +} + +static bool lvts_should_update_thresh(struct lvts_ctrl *lvts_ctrl, int high) +{ + int i; + + if (high > lvts_ctrl->high_thresh) + return true; + + for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++) + if (lvts_ctrl->sensors[i].high_thresh == lvts_ctrl->high_thresh + && lvts_ctrl->sensors[i].low_thresh == lvts_ctrl->low_thresh) + return false; + + return true; +} + static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high) { struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz); + struct lvts_ctrl *lvts_ctrl = container_of(lvts_sensor, struct lvts_ctrl, sensors[lvts_sensor->id]); void __iomem *base = lvts_sensor->base; u32 raw_low = lvts_temp_to_raw(low != -INT_MAX ? low : LVTS_MINIMUM_THRESHOLD); u32 raw_high = lvts_temp_to_raw(high); + bool should_update_thresh; + + lvts_sensor->low_thresh = low; + lvts_sensor->high_thresh = high; + + should_update_thresh = lvts_should_update_thresh(lvts_ctrl, high); + if (should_update_thresh) { + lvts_ctrl->high_thresh = high; + lvts_ctrl->low_thresh = low; + } + lvts_update_irq_mask(lvts_ctrl); + + if (!should_update_thresh) + return 0; /* * Low offset temperature threshold @@ -521,6 +584,9 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl, */ lvts_sensor[i].msr = lvts_ctrl_data->mode == LVTS_MSR_IMMEDIATE_MODE ? imm_regs[i] : msr_regs[i]; + + lvts_sensor[i].low_thresh = INT_MIN; + lvts_sensor[i].high_thresh = INT_MIN; }; lvts_ctrl->num_lvts_sensor = lvts_ctrl_data->num_lvts_sensor; @@ -688,6 +754,9 @@ static int lvts_ctrl_init(struct device *dev, struct lvts_domain *lvts_td, */ lvts_ctrl[i].hw_tshut_raw_temp = lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp); + + lvts_ctrl[i].low_thresh = INT_MIN; + lvts_ctrl[i].high_thresh = INT_MIN; } /* -- GitLab From 19ad9f29751ca385262c63f513f75610962c40a0 Mon Sep 17 00:00:00 2001 From: Minjie Du Date: Thu, 13 Jul 2023 12:24:12 +0800 Subject: [PATCH 1122/3445] thermal/drivers/mediatek/lvts: Fix parameter check in lvts_debugfs_init() The documentation says "If an error occurs, ERR_PTR(-ERROR) will be returned" but the current code checks against a NULL pointer returned. Fix this by checking if IS_ERR(). Signed-off-by: Minjie Du Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230713042413.2519-1-duminjie@vivo.com --- drivers/thermal/mediatek/lvts_thermal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c index 61c3de44c40ba..bc726ac0a672e 100644 --- a/drivers/thermal/mediatek/lvts_thermal.c +++ b/drivers/thermal/mediatek/lvts_thermal.c @@ -201,7 +201,7 @@ static int lvts_debugfs_init(struct device *dev, struct lvts_domain *lvts_td) int i; lvts_td->dom_dentry = debugfs_create_dir(dev_name(dev), NULL); - if (!lvts_td->dom_dentry) + if (IS_ERR(lvts_td->dom_dentry)) return 0; for (i = 0; i < lvts_td->num_lvts_ctrl; i++) { -- GitLab From 4afcb58ea47e66c025d2b0a5f091dce5aaf95b0f Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Sat, 8 Jul 2023 13:26:46 +0200 Subject: [PATCH 1123/3445] thermal/drivers/imx8mm: Suppress log message on probe deferral nvmem_cell_read_u32() may return -EPROBE_DEFER if NVMEM supplier has not yet been probed. Future reprobe may succeed, so printing: i.mx8mm_thermal 30260000.tmu: Failed to read OCOTP nvmem cell (-517). to the log is confusing. Fix this by using dev_err_probe. This also elevates the message from warning to error, which is more correct: The log message is only ever printed in probe error path and probe aborts afterwards, so it really warrants an error-level message. Fixes: 403291648823 ("thermal/drivers/imx: Add support for loading calibration data from OCOTP") Signed-off-by: Ahmad Fatoum Reviewed-by: Marek Vasut Reviewed-by: Peng Fan Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230708112647.2897294-1-a.fatoum@pengutronix.de --- drivers/thermal/imx8mm_thermal.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/thermal/imx8mm_thermal.c b/drivers/thermal/imx8mm_thermal.c index e89b11b3f2b93..14111ccf6e4c2 100644 --- a/drivers/thermal/imx8mm_thermal.c +++ b/drivers/thermal/imx8mm_thermal.c @@ -178,10 +178,8 @@ static int imx8mm_tmu_probe_set_calib_v1(struct platform_device *pdev, int ret; ret = nvmem_cell_read_u32(&pdev->dev, "calib", &ana0); - if (ret) { - dev_warn(dev, "Failed to read OCOTP nvmem cell (%d).\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to read OCOTP nvmem cell\n"); writel(FIELD_PREP(TASR_BUF_VREF_MASK, FIELD_GET(ANA0_BUF_VREF_MASK, ana0)) | -- GitLab From 02cf5bcbd0a0283ecc13cceceeb43de45d79c85e Mon Sep 17 00:00:00 2001 From: Min-Hua Chen Date: Fri, 14 Jul 2023 00:04:14 +0800 Subject: [PATCH 1124/3445] thermal/drivers/tsens: Make tsens_xxxx_nvmem static This patch fixes the following sparse warnings: drivers/thermal/qcom/tsens-v1.c:24:40: sparse: warning: symbol 'tsens_qcs404_nvmem' was not declared. Should it be static? drivers/thermal/qcom/tsens-v0_1.c:26:40: sparse: warning: symbol 'tsens_8916_nvmem' was not declared. Should it be static? drivers/thermal/qcom/tsens-v0_1.c:42:40: sparse: warning: symbol 'tsens_8974_nvmem' was not declared. Should it be static? drivers/thermal/qcom/tsens-v0_1.c:64:40: sparse: warning: symbol 'tsens_8974_backup_nvmem' was not declared. Should it be static? No functional change intended. Signed-off-by: Min-Hua Chen Reviewed-by: Dmitry Baryshkov Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230713160415.149381-1-minhuadotchen@gmail.com --- drivers/thermal/qcom/tsens-v0_1.c | 6 +++--- drivers/thermal/qcom/tsens-v1.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/thermal/qcom/tsens-v0_1.c b/drivers/thermal/qcom/tsens-v0_1.c index a941b4241b0ab..87c09f62ee816 100644 --- a/drivers/thermal/qcom/tsens-v0_1.c +++ b/drivers/thermal/qcom/tsens-v0_1.c @@ -23,7 +23,7 @@ #define BIT_APPEND 0x3 -struct tsens_legacy_calibration_format tsens_8916_nvmem = { +static struct tsens_legacy_calibration_format tsens_8916_nvmem = { .base_len = 7, .base_shift = 3, .sp_len = 5, @@ -39,7 +39,7 @@ struct tsens_legacy_calibration_format tsens_8916_nvmem = { }, }; -struct tsens_legacy_calibration_format tsens_8974_nvmem = { +static struct tsens_legacy_calibration_format tsens_8974_nvmem = { .base_len = 8, .base_shift = 2, .sp_len = 6, @@ -61,7 +61,7 @@ struct tsens_legacy_calibration_format tsens_8974_nvmem = { }, }; -struct tsens_legacy_calibration_format tsens_8974_backup_nvmem = { +static struct tsens_legacy_calibration_format tsens_8974_backup_nvmem = { .base_len = 8, .base_shift = 2, .sp_len = 6, diff --git a/drivers/thermal/qcom/tsens-v1.c b/drivers/thermal/qcom/tsens-v1.c index 51322430f1fe1..dc1c4ae2d8b01 100644 --- a/drivers/thermal/qcom/tsens-v1.c +++ b/drivers/thermal/qcom/tsens-v1.c @@ -21,7 +21,7 @@ #define TM_HIGH_LOW_INT_STATUS_OFF 0x0088 #define TM_HIGH_LOW_Sn_INT_THRESHOLD_OFF 0x0090 -struct tsens_legacy_calibration_format tsens_qcs404_nvmem = { +static struct tsens_legacy_calibration_format tsens_qcs404_nvmem = { .base_len = 8, .base_shift = 2, .sp_len = 6, -- GitLab From f664a6b5a9740ae5f4a8c36d01ba0752a1f4a0e0 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 26 Jun 2023 20:55:15 +0800 Subject: [PATCH 1125/3445] thermal/drivers/sun8i: Remove unneeded comments It's redundant, let's remove it. Signed-off-by: Yangtao Li Acked-by: Jernej Skrabec Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230626125515.18830-1-frank.li@vivo.com --- drivers/thermal/sun8i_thermal.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/thermal/sun8i_thermal.c b/drivers/thermal/sun8i_thermal.c index cca16d632d9fc..c38d5f1f212d7 100644 --- a/drivers/thermal/sun8i_thermal.c +++ b/drivers/thermal/sun8i_thermal.c @@ -56,8 +56,6 @@ #define SUN50I_H6_THS_PC_TEMP_PERIOD(x) ((GENMASK(19, 0) & (x)) << 12) #define SUN50I_H6_THS_DATA_IRQ_STS(x) BIT(x) -/* millidegree celsius */ - struct tsensor { struct ths_device *tmdev; struct thermal_zone_device *tzd; -- GitLab From c51592a95f360aabf2b8a5691c550e1749dc41eb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 19 Jul 2023 01:58:54 +0100 Subject: [PATCH 1126/3445] thermal/drivers/sun8i: Free calibration nvmem after reading it The sun8i thermal driver reads calibration data via the nvmem API at startup, updating the device configuration and not referencing the data again. Rather than explicitly freeing the nvmem data the driver relies on devm_ to release it, even though the data is never referenced again. The allocation is still tracked so it's not leaked but this is notable when looking at the code and is a little wasteful so let's instead explicitly free the nvmem after we're done with it. Signed-off-by: Mark Brown Acked-by: Jernej Skrabec Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230719-thermal-sun8i-free-nvmem-v1-1-f553d5afef79@kernel.org --- drivers/thermal/sun8i_thermal.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/thermal/sun8i_thermal.c b/drivers/thermal/sun8i_thermal.c index c38d5f1f212d7..702d4d4faaedf 100644 --- a/drivers/thermal/sun8i_thermal.c +++ b/drivers/thermal/sun8i_thermal.c @@ -284,7 +284,7 @@ static int sun8i_ths_calibrate(struct ths_device *tmdev) size_t callen; int ret = 0; - calcell = devm_nvmem_cell_get(dev, "calibration"); + calcell = nvmem_cell_get(dev, "calibration"); if (IS_ERR(calcell)) { if (PTR_ERR(calcell) == -EPROBE_DEFER) return -EPROBE_DEFER; @@ -314,6 +314,8 @@ static int sun8i_ths_calibrate(struct ths_device *tmdev) kfree(caldata); out: + if (!IS_ERR(calcell)) + nvmem_cell_put(calcell); return ret; } -- GitLab From 92382d744176f230101d54f5c017bccd62770f01 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Mon, 7 Aug 2023 08:36:28 -0700 Subject: [PATCH 1127/3445] lib: test_scanf: Add explicit type cast to result initialization in test_number_prefix() A recent change in clang allows it to consider more expressions as compile time constants, which causes it to point out an implicit conversion in the scanf tests: lib/test_scanf.c:661:2: warning: implicit conversion from 'int' to 'unsigned char' changes value from -168 to 88 [-Wconstant-conversion] 661 | test_number_prefix(unsigned char, "0xA7", "%2hhx%hhx", 0, 0xa7, 2, check_uchar); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ lib/test_scanf.c:609:29: note: expanded from macro 'test_number_prefix' 609 | T result[2] = {~expect[0], ~expect[1]}; \ | ~ ^~~~~~~~~~ 1 warning generated. The result of the bitwise negation is the type of the operand after going through the integer promotion rules, so this truncation is expected but harmless, as the initial values in the result array get overwritten by _test() anyways. Add an explicit cast to the expected type in test_number_prefix() to silence the warning. There is no functional change, as all the tests still pass with GCC 13.1.0 and clang 18.0.0. Cc: stable@vger.kernel.org Link: https://github.com/ClangBuiltLinux/linuxq/issues/1899 Link: https://github.com/llvm/llvm-project/commit/610ec954e1f81c0e8fcadedcd25afe643f5a094e Suggested-by: Nick Desaulniers Signed-off-by: Nathan Chancellor Reviewed-by: Petr Mladek Signed-off-by: Petr Mladek Link: https://lore.kernel.org/r/20230807-test_scanf-wconstant-conversion-v2-1-839ca39083e1@kernel.org --- lib/test_scanf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/test_scanf.c b/lib/test_scanf.c index b620cf7de5035..a2707af2951ab 100644 --- a/lib/test_scanf.c +++ b/lib/test_scanf.c @@ -606,7 +606,7 @@ static void __init numbers_slice(void) #define test_number_prefix(T, str, scan_fmt, expect0, expect1, n_args, fn) \ do { \ const T expect[2] = { expect0, expect1 }; \ - T result[2] = {~expect[0], ~expect[1]}; \ + T result[2] = { (T)~expect[0], (T)~expect[1] }; \ \ _test(fn, &expect, str, scan_fmt, n_args, &result[0], &result[1]); \ } while (0) -- GitLab From e9b1de73b7ca31f487e4f4f063a5b70aeb707863 Mon Sep 17 00:00:00 2001 From: Chen Jiahao Date: Wed, 2 Aug 2023 17:45:27 +0800 Subject: [PATCH 1128/3445] thermal/drivers/mediatek: Clean up redundant dev_err_probe() Referring to platform_get_irq()'s definition, the return value has already been checked if ret < 0, and printed via dev_err_probe(). Calling dev_err_probe() one more time outside platform_get_irq() is obviously redundant. Removing dev_err_probe() outside platform_get_irq() to clean up above problem. Signed-off-by: Chen Jiahao Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230802094527.988842-1-chenjiahao16@huawei.com --- drivers/thermal/mediatek/lvts_thermal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c index bc726ac0a672e..f4709ae842a26 100644 --- a/drivers/thermal/mediatek/lvts_thermal.c +++ b/drivers/thermal/mediatek/lvts_thermal.c @@ -1216,7 +1216,7 @@ static int lvts_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) - return dev_err_probe(dev, irq, "No irq resource\n"); + return irq; ret = lvts_domain_init(dev, lvts_td, lvts_data); if (ret) -- GitLab From c39300c47d9195928fc1145f789fb0f36e471779 Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Wed, 9 Aug 2023 18:14:39 +0800 Subject: [PATCH 1129/3445] thermal/drivers/db8500: Remove redundant of_match_ptr() The driver depends on CONFIG_OF, it is not necessary to use of_match_ptr() here. Signed-off-by: Ruan Jinjie Reviewed-by: Linus Walleij Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230809101439.2663042-1-ruanjinjie@huawei.com --- drivers/thermal/db8500_thermal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/db8500_thermal.c b/drivers/thermal/db8500_thermal.c index fca5c2c93bf97..576f88b6a1b35 100644 --- a/drivers/thermal/db8500_thermal.c +++ b/drivers/thermal/db8500_thermal.c @@ -229,7 +229,7 @@ MODULE_DEVICE_TABLE(of, db8500_thermal_match); static struct platform_driver db8500_thermal_driver = { .driver = { .name = "db8500-thermal", - .of_match_table = of_match_ptr(db8500_thermal_match), + .of_match_table = db8500_thermal_match, }, .probe = db8500_thermal_probe, .suspend = db8500_thermal_suspend, -- GitLab From 1892f9f01cd0cf163d2a2ee182d60d61e9d95be0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 10 Aug 2023 11:13:18 +0200 Subject: [PATCH 1130/3445] thermal/drivers/samsung: Fix Wvoid-pointer-to-enum-cast warning 'soc' is an enum, thus cast of pointer on 64-bit compile test with W=1 causes: exynos_tmu.c:890:14: error: cast to smaller integer type 'enum soc_type' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] Signed-off-by: Krzysztof Kozlowski Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230810091318.70261-1-krzysztof.kozlowski@linaro.org --- drivers/thermal/samsung/exynos_tmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index 58f4d8f7a3fd6..e5bc2c82010f9 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -887,7 +887,7 @@ static int exynos_map_dt_data(struct platform_device *pdev) return -EADDRNOTAVAIL; } - data->soc = (enum soc_type)of_device_get_match_data(&pdev->dev); + data->soc = (uintptr_t)of_device_get_match_data(&pdev->dev); switch (data->soc) { case SOC_ARCH_EXYNOS4210: -- GitLab From 1c73c3be9cc83ad1340897fe45adf1d11c418678 Mon Sep 17 00:00:00 2001 From: Andrei Coardos Date: Thu, 10 Aug 2023 14:13:30 +0300 Subject: [PATCH 1131/3445] thermal/drivers/broadcom/sr-thermal: Removed call to platform_set_drvdata() This function call was found to be unnecessary as there is no equivalent platform_get_drvdata() call to access the private data of the driver. Also, the private data is defined in this driver, so there is no risk of it being accessed outside of this driver file. Signed-off-by: Andrei Coardos Reviewed-by: Alexandru Ardelean Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230810111330.3248-1-aboutphysycs@gmail.com --- drivers/thermal/broadcom/sr-thermal.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/thermal/broadcom/sr-thermal.c b/drivers/thermal/broadcom/sr-thermal.c index 7479158900226..9a29dfd4c7fe5 100644 --- a/drivers/thermal/broadcom/sr-thermal.c +++ b/drivers/thermal/broadcom/sr-thermal.c @@ -91,7 +91,6 @@ static int sr_thermal_probe(struct platform_device *pdev) dev_dbg(dev, "thermal sensor %d registered\n", i); } - platform_set_drvdata(pdev, sr_thermal); return 0; } -- GitLab From e51c521692362d7c32a28fbce21f88f703013a12 Mon Sep 17 00:00:00 2001 From: Andrei Coardos Date: Thu, 10 Aug 2023 14:20:15 +0300 Subject: [PATCH 1132/3445] thermal/drivers/k3_j72xx_bandgap: Removed unneeded call to platform_set_drvdata() This function call was found to be unnecessary as there is no equivalent platform_get_drvdata() call to access the private data of the driver. Also, the private data is defined in this driver, so there is no risk of it being accessed outside of this driver file. Signed-off-by: Andrei Coardos Reviewed-by: Alexandru Ardelean Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230810112015.3578-1-aboutphysycs@gmail.com --- drivers/thermal/k3_j72xx_bandgap.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/thermal/k3_j72xx_bandgap.c b/drivers/thermal/k3_j72xx_bandgap.c index a5a0fc9b9356f..2fc799b07b909 100644 --- a/drivers/thermal/k3_j72xx_bandgap.c +++ b/drivers/thermal/k3_j72xx_bandgap.c @@ -502,8 +502,6 @@ static int k3_j72xx_bandgap_probe(struct platform_device *pdev) writel(K3_VTM_ANYMAXT_OUTRG_ALERT_EN, data[0].bgp->cfg2_base + K3_VTM_MISC_CTRL_OFFSET); - platform_set_drvdata(pdev, bgp); - print_look_up_table(dev, ref_table); /* * Now that the derived_table has the appropriate look up values -- GitLab From 3ee1f79426acb77ff131be025963fe223ad2ee02 Mon Sep 17 00:00:00 2001 From: Andrei Coardos Date: Thu, 10 Aug 2023 14:23:44 +0300 Subject: [PATCH 1133/3445] thermal/drivers/k3_bandgap: Remove unneeded call to platform_set_drvdata() This function call was found to be unnecessary as there is no equivalent platform_get_drvdata() call to access the private data of the driver. Also, the private data is defined in this driver, so there is no risk of it being accessed outside of this driver file. Signed-off-by: Andrei Coardos Reviewed-by: Alexandru Ardelean Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230810112344.3806-1-aboutphysycs@gmail.com --- drivers/thermal/k3_bandgap.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/thermal/k3_bandgap.c b/drivers/thermal/k3_bandgap.c index 68f59b3735d3b..4a918c1e92f9b 100644 --- a/drivers/thermal/k3_bandgap.c +++ b/drivers/thermal/k3_bandgap.c @@ -225,7 +225,6 @@ static int k3_bandgap_probe(struct platform_device *pdev) devm_thermal_add_hwmon_sysfs(dev, data[id].tzd); } - platform_set_drvdata(pdev, bgp); return 0; -- GitLab From 80e4f25262f9f1a5f08154fafaa6ac4371043d35 Mon Sep 17 00:00:00 2001 From: Hao Xu Date: Tue, 1 Aug 2023 16:06:45 +0800 Subject: [PATCH 1134/3445] fuse: invalidate page cache pages before direct write In FOPEN_DIRECT_IO, page cache may still be there for a file since private mmap is allowed. Direct write should respect that and invalidate the corresponding pages so that page cache readers don't get stale data. Signed-off-by: Hao Xu Tested-by: Jiachen Zhang Signed-off-by: Miklos Szeredi --- fs/fuse/file.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 1c7599ed90625..1aa7dde665aa1 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1428,7 +1428,8 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter, int write = flags & FUSE_DIO_WRITE; int cuse = flags & FUSE_DIO_CUSE; struct file *file = io->iocb->ki_filp; - struct inode *inode = file->f_mapping->host; + struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; struct fuse_file *ff = file->private_data; struct fuse_conn *fc = ff->fm->fc; size_t nmax = write ? fc->max_write : fc->max_read; @@ -1440,6 +1441,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter, int err = 0; struct fuse_io_args *ia; unsigned int max_pages; + bool fopen_direct_io = ff->open_flags & FOPEN_DIRECT_IO; max_pages = iov_iter_npages(iter, fc->max_pages); ia = fuse_io_alloc(io, max_pages); @@ -1454,6 +1456,14 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter, inode_unlock(inode); } + if (fopen_direct_io && write) { + res = invalidate_inode_pages2_range(mapping, idx_from, idx_to); + if (res) { + fuse_io_free(ia); + return res; + } + } + io->should_dirty = !write && user_backed_iter(iter); while (count) { ssize_t nres; -- GitLab From 185673ca71d3f7e9c7d62ee5084348e084352e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= Date: Thu, 13 Jul 2023 11:42:37 -0400 Subject: [PATCH 1135/3445] thermal/drivers/mediatek/lvts_thermal: Make readings valid in filtered mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, when a controller is configured to use filtered mode, thermal readings are valid only about 30% of the time. Upon testing, it was noticed that lowering any of the interval settings resulted in an improved rate of valid data. The same was observed when decreasing the number of samples for each sensor (which also results in quicker measurements). Retrying the read with a timeout longer than the time it takes to resample (about 344us with these settings and 4 sensors) also improves the rate. Lower all timing settings to the minimum, configure the filtering to single sample, and poll the measurement register for at least one period to improve the data validity on filtered mode. With these changes in place, out of 100000 reads, a single one failed, ie 99.999% of the data was valid. Reviewed-by: Chen-Yu Tsai Tested-by: Chen-Yu Tsai Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: Alexandre Mergnat Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230713154743.611870-1-nfraprado@collabora.com --- drivers/thermal/mediatek/lvts_thermal.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c index f4709ae842a26..effd9b00a424b 100644 --- a/drivers/thermal/mediatek/lvts_thermal.c +++ b/drivers/thermal/mediatek/lvts_thermal.c @@ -58,11 +58,11 @@ #define LVTS_PROTTC(__base) (__base + 0x00CC) #define LVTS_CLKEN(__base) (__base + 0x00E4) -#define LVTS_PERIOD_UNIT ((118 * 1000) / (256 * 38)) -#define LVTS_GROUP_INTERVAL 1 -#define LVTS_FILTER_INTERVAL 1 -#define LVTS_SENSOR_INTERVAL 1 -#define LVTS_HW_FILTER 0x2 +#define LVTS_PERIOD_UNIT 0 +#define LVTS_GROUP_INTERVAL 0 +#define LVTS_FILTER_INTERVAL 0 +#define LVTS_SENSOR_INTERVAL 0 +#define LVTS_HW_FILTER 0x0 #define LVTS_TSSEL_CONF 0x13121110 #define LVTS_CALSCALE_CONF 0x300 #define LVTS_MONINT_CONF 0x8300318C @@ -86,6 +86,9 @@ #define LVTS_MSR_IMMEDIATE_MODE 0 #define LVTS_MSR_FILTERED_MODE 1 +#define LVTS_MSR_READ_TIMEOUT_US 400 +#define LVTS_MSR_READ_WAIT_US (LVTS_MSR_READ_TIMEOUT_US / 2) + #define LVTS_HW_SHUTDOWN_MT8195 105000 #define LVTS_MINIMUM_THRESHOLD 20000 @@ -268,6 +271,7 @@ static int lvts_get_temp(struct thermal_zone_device *tz, int *temp) struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz); void __iomem *msr = lvts_sensor->msr; u32 value; + int rc; /* * Measurement registers: @@ -280,7 +284,8 @@ static int lvts_get_temp(struct thermal_zone_device *tz, int *temp) * 16 : Valid temperature * 15-0 : Raw temperature */ - value = readl(msr); + rc = readl_poll_timeout(msr, value, value & BIT(16), + LVTS_MSR_READ_WAIT_US, LVTS_MSR_READ_TIMEOUT_US); /* * As the thermal zone temperature will read before the @@ -293,7 +298,7 @@ static int lvts_get_temp(struct thermal_zone_device *tz, int *temp) * functionning temperature and directly jump to a system * shutdown. */ - if (!(value & BIT(16))) + if (rc) return -EAGAIN; *temp = lvts_raw_to_temp(value & 0xFFFF); -- GitLab From fb6ce327d6ad382d46b30fa79cae763d5bc457ae Mon Sep 17 00:00:00 2001 From: Andrei Coardos Date: Wed, 9 Aug 2023 18:48:13 +0300 Subject: [PATCH 1136/3445] thermal/drivers/broadcom/brcstb_thermal: Removed unneeded platform_set_drvdata() This function call was found to be unnecessary as there is no equivalent platform_get_drvdata() call to access the private data of the driver. Also, the private data is defined in this driver, so there is no risk of it being accessed outside of this driver file. Signed-off-by: Andrei Coardos Reviewed-by: Alexandru Ardelean Reviewed-by: Florian Fainelli Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230809154813.16033-1-aboutphysycs@gmail.com --- drivers/thermal/broadcom/brcmstb_thermal.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/thermal/broadcom/brcmstb_thermal.c b/drivers/thermal/broadcom/brcmstb_thermal.c index 0b73abdaa792a..9674e5ffcfa27 100644 --- a/drivers/thermal/broadcom/brcmstb_thermal.c +++ b/drivers/thermal/broadcom/brcmstb_thermal.c @@ -334,7 +334,6 @@ static int brcmstb_thermal_probe(struct platform_device *pdev) return PTR_ERR(priv->tmon_base); priv->dev = &pdev->dev; - platform_set_drvdata(pdev, priv); of_ops = priv->temp_params->of_ops; thermal = devm_thermal_of_zone_register(&pdev->dev, 0, priv, -- GitLab From f4636b5587842042d883d6ab646289baabba9c5a Mon Sep 17 00:00:00 2001 From: Andrei Coardos Date: Fri, 11 Aug 2023 22:40:32 +0300 Subject: [PATCH 1137/3445] thermal/drivers/sun8i_thermal: Remove unneeded call to platform_set_drvdata() This function call was found to be unnecessary as there is no equivalent platform_get_drvdata() call to access the private data of the driver. Also, the private data is defined in this driver, so there is no risk of it being accessed outside of this driver file. Signed-off-by: Andrei Coardos Reviewed-by: Jernej Skrabec Reviewed-by: Alexandru Ardelean Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230811194032.4240-1-aboutphysycs@gmail.com --- drivers/thermal/sun8i_thermal.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/thermal/sun8i_thermal.c b/drivers/thermal/sun8i_thermal.c index 702d4d4faaedf..f989b55a8aa8e 100644 --- a/drivers/thermal/sun8i_thermal.c +++ b/drivers/thermal/sun8i_thermal.c @@ -489,8 +489,6 @@ static int sun8i_ths_probe(struct platform_device *pdev) if (!tmdev->chip) return -EINVAL; - platform_set_drvdata(pdev, tmdev); - ret = sun8i_ths_resource_init(tmdev); if (ret) return ret; -- GitLab From ec6a51927ed3596e16aae0ad9f5762ecaa2af656 Mon Sep 17 00:00:00 2001 From: Andrei Coardos Date: Fri, 11 Aug 2023 22:28:47 +0300 Subject: [PATCH 1138/3445] thermal/drivers/mediatek/auxadc_thermal: Removed call to platform_set_drvdata() This function call was found to be unnecessary as there is no equivalent platform_get_drvdata() call to access the private data of the driver. Also, the private data is defined in this driver, so there is no risk of it being accessed outside of this driver file. Signed-off-by: Andrei Coardos Reviewed-by: Alexandru Ardelean Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230811192847.3838-1-aboutphysycs@gmail.com --- drivers/thermal/mediatek/auxadc_thermal.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/thermal/mediatek/auxadc_thermal.c b/drivers/thermal/mediatek/auxadc_thermal.c index c537aed710177..843214d30bd8b 100644 --- a/drivers/thermal/mediatek/auxadc_thermal.c +++ b/drivers/thermal/mediatek/auxadc_thermal.c @@ -1282,8 +1282,6 @@ static int mtk_thermal_probe(struct platform_device *pdev) mtk_thermal_init_bank(mt, i, apmixed_phys_base, auxadc_phys_base, ctrl_id); - platform_set_drvdata(pdev, mt); - tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt, &mtk_thermal_ops); if (IS_ERR(tzdev)) -- GitLab From 72449b3a21b9c5ffd6db2607d33d5e6b0cd85062 Mon Sep 17 00:00:00 2001 From: Andrei Coardos Date: Fri, 11 Aug 2023 22:15:48 +0300 Subject: [PATCH 1139/3445] thermal/drivers/max77620_thermal: Removed unneeded call to platform_set_drvdata() This function call was found to be unnecessary as there is no equivalent platform_get_drvdata() call to access the private data of the driver. Also, the private data is defined in this driver, so there is no risk of it being accessed outside of this driver file. Signed-off-by: Andrei Coardos Reviewed-by: Alexandru Ardelean Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230811191548.3340-1-aboutphysycs@gmail.com --- drivers/thermal/max77620_thermal.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/thermal/max77620_thermal.c b/drivers/thermal/max77620_thermal.c index 61c7622d9945d..919b6ee208d81 100644 --- a/drivers/thermal/max77620_thermal.c +++ b/drivers/thermal/max77620_thermal.c @@ -139,8 +139,6 @@ static int max77620_thermal_probe(struct platform_device *pdev) return ret; } - platform_set_drvdata(pdev, mtherm); - return 0; } -- GitLab From 01c2180b7099aac7902472a2204562397592782f Mon Sep 17 00:00:00 2001 From: Andrei Coardos Date: Mon, 14 Aug 2023 21:09:21 +0300 Subject: [PATCH 1140/3445] thermal/drivers/generic-adc: Removed unneeded call to platform_set_drvdata() This function call was found to be unnecessary as there is no equivalent platform_get_drvdata() call to access the private data of the driver. Also, the private data is defined in this driver, so there is no risk of it being accessed outside of this driver file. Signed-off-by: Andrei Coardos Reviewed-by: Alexandru Ardelean Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20230814180921.3336-1-aboutphysycs@gmail.com --- drivers/thermal/thermal-generic-adc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/thermal/thermal-generic-adc.c b/drivers/thermal/thermal-generic-adc.c index f4f1a04f8c0f3..1717e4a19dcbf 100644 --- a/drivers/thermal/thermal-generic-adc.c +++ b/drivers/thermal/thermal-generic-adc.c @@ -142,7 +142,6 @@ static int gadc_thermal_probe(struct platform_device *pdev) return ret; gti->dev = &pdev->dev; - platform_set_drvdata(pdev, gti); gti->tz_dev = devm_thermal_of_zone_register(&pdev->dev, 0, gti, &gadc_thermal_ops); -- GitLab From e78662e818f9478e70912cc2970ca632ec9f3635 Mon Sep 17 00:00:00 2001 From: Hao Xu Date: Tue, 1 Aug 2023 16:06:46 +0800 Subject: [PATCH 1141/3445] fuse: add a new fuse init flag to relax restrictions in no cache mode FOPEN_DIRECT_IO is usually set by fuse daemon to indicate need of strong coherency, e.g. network filesystems. Thus shared mmap is disabled since it leverages page cache and may write to it, which may cause inconsistence. But FOPEN_DIRECT_IO can be used not for coherency but to reduce memory footprint as well, e.g. reduce guest memory usage with virtiofs. Therefore, add a new fuse init flag FUSE_DIRECT_IO_RELAX to relax restrictions in that mode, currently, it allows shared mmap. One thing to note is to make sure it doesn't break coherency in your use case. Signed-off-by: Hao Xu Signed-off-by: Miklos Szeredi --- fs/fuse/file.c | 7 +++++-- fs/fuse/fuse_i.h | 3 +++ fs/fuse/inode.c | 4 +++- include/uapi/linux/fuse.h | 8 +++++++- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 1aa7dde665aa1..e6034ce698e99 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -2451,14 +2451,17 @@ static const struct vm_operations_struct fuse_file_vm_ops = { static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma) { struct fuse_file *ff = file->private_data; + struct fuse_conn *fc = ff->fm->fc; /* DAX mmap is superior to direct_io mmap */ if (FUSE_IS_DAX(file_inode(file))) return fuse_dax_mmap(file, vma); if (ff->open_flags & FOPEN_DIRECT_IO) { - /* Can't provide the coherency needed for MAP_SHARED */ - if (vma->vm_flags & VM_MAYSHARE) + /* Can't provide the coherency needed for MAP_SHARED + * if FUSE_DIRECT_IO_RELAX isn't set. + */ + if ((vma->vm_flags & VM_MAYSHARE) && !fc->direct_io_relax) return -ENODEV; invalidate_inode_pages2(file->f_mapping); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 9b7fc7d3c7f15..d830c2360aefd 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -792,6 +792,9 @@ struct fuse_conn { /* Is tmpfile not implemented by fs? */ unsigned int no_tmpfile:1; + /* relax restrictions in FOPEN_DIRECT_IO mode */ + unsigned int direct_io_relax:1; + /** The number of requests waiting for completion */ atomic_t num_waiting; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index f19d748890f08..4a16185eacae7 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -1212,6 +1212,8 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args, fc->init_security = 1; if (flags & FUSE_CREATE_SUPP_GROUP) fc->create_supp_group = 1; + if (flags & FUSE_DIRECT_IO_RELAX) + fc->direct_io_relax = 1; } else { ra_pages = fc->max_read / PAGE_SIZE; fc->no_lock = 1; @@ -1258,7 +1260,7 @@ void fuse_send_init(struct fuse_mount *fm) FUSE_NO_OPENDIR_SUPPORT | FUSE_EXPLICIT_INVAL_DATA | FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT | FUSE_INIT_EXT | FUSE_SECURITY_CTX | FUSE_CREATE_SUPP_GROUP | - FUSE_HAS_EXPIRE_ONLY; + FUSE_HAS_EXPIRE_ONLY | FUSE_DIRECT_IO_RELAX; #ifdef CONFIG_FUSE_DAX if (fm->fc->dax) flags |= FUSE_MAP_ALIGNMENT; diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index b3fcab13fcd3d..c2da9503b04e1 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -207,6 +207,9 @@ * - add FUSE_EXT_GROUPS * - add FUSE_CREATE_SUPP_GROUP * - add FUSE_HAS_EXPIRE_ONLY + * + * 7.39 + * - add FUSE_DIRECT_IO_RELAX */ #ifndef _LINUX_FUSE_H @@ -242,7 +245,7 @@ #define FUSE_KERNEL_VERSION 7 /** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 38 +#define FUSE_KERNEL_MINOR_VERSION 39 /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 @@ -371,6 +374,8 @@ struct fuse_file_lock { * FUSE_CREATE_SUPP_GROUP: add supplementary group info to create, mkdir, * symlink and mknod (single group that matches parent) * FUSE_HAS_EXPIRE_ONLY: kernel supports expiry-only entry invalidation + * FUSE_DIRECT_IO_RELAX: relax restrictions in FOPEN_DIRECT_IO mode, for now + * allow shared mmap */ #define FUSE_ASYNC_READ (1 << 0) #define FUSE_POSIX_LOCKS (1 << 1) @@ -409,6 +414,7 @@ struct fuse_file_lock { #define FUSE_HAS_INODE_DAX (1ULL << 33) #define FUSE_CREATE_SUPP_GROUP (1ULL << 34) #define FUSE_HAS_EXPIRE_ONLY (1ULL << 35) +#define FUSE_DIRECT_IO_RELAX (1ULL << 36) /** * CUSE INIT request/reply flags -- GitLab From b5a2a3a0b77668257fa72ee6bc0eac90493f13c1 Mon Sep 17 00:00:00 2001 From: Hao Xu Date: Tue, 1 Aug 2023 16:06:47 +0800 Subject: [PATCH 1142/3445] fuse: write back dirty pages before direct write in direct_io_relax mode In direct_io_relax mode, there can be shared mmaped files and thus dirty pages in its page cache. Therefore those dirty pages should be written back to backend before direct io to avoid data loss. Signed-off-by: Hao Xu Reviewed-by: Jiachen Zhang Signed-off-by: Miklos Szeredi --- fs/fuse/file.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index e6034ce698e99..1cdb6327511ef 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1448,6 +1448,13 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter, if (!ia) return -ENOMEM; + if (fopen_direct_io && fc->direct_io_relax) { + res = filemap_write_and_wait_range(mapping, pos, pos + count - 1); + if (res) { + fuse_io_free(ia); + return res; + } + } if (!cuse && fuse_range_is_writeback(inode, idx_from, idx_to)) { if (!write) inode_lock(inode); -- GitLab From 8d8f9c4b8df6bc2bf005c91b73b23a0e60f0e413 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 10 Aug 2023 12:45:05 +0200 Subject: [PATCH 1143/3445] fuse: handle empty request_mask in statx If no attribute is requested, then don't send request to userspace. Signed-off-by: Miklos Szeredi --- fs/fuse/dir.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index f67bef9d83c4b..d38ab93e20077 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1209,7 +1209,12 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file, u32 inval_mask = READ_ONCE(fi->inval_mask); u32 cache_mask = fuse_get_cache_mask(inode); - if (flags & AT_STATX_FORCE_SYNC) + /* FUSE only supports basic stats */ + request_mask &= STATX_BASIC_STATS; + + if (!request_mask) + sync = false; + else if (flags & AT_STATX_FORCE_SYNC) sync = true; else if (flags & AT_STATX_DONT_SYNC) sync = false; -- GitLab From ba58a37c2847f21494a04240fb48955cbd5d1aca Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 10 Aug 2023 12:45:05 +0200 Subject: [PATCH 1144/3445] fuse: add STATX request Use the same structure as statx. Signed-off-by: Miklos Szeredi --- include/uapi/linux/fuse.h | 52 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index c2da9503b04e1..db92a7202b342 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -210,6 +210,7 @@ * * 7.39 * - add FUSE_DIRECT_IO_RELAX + * - add FUSE_STATX and related structures */ #ifndef _LINUX_FUSE_H @@ -272,6 +273,40 @@ struct fuse_attr { uint32_t flags; }; +/* + * The following structures are bit-for-bit compatible with the statx(2) ABI in + * Linux. + */ +struct fuse_sx_time { + int64_t tv_sec; + uint32_t tv_nsec; + int32_t __reserved; +}; + +struct fuse_statx { + uint32_t mask; + uint32_t blksize; + uint64_t attributes; + uint32_t nlink; + uint32_t uid; + uint32_t gid; + uint16_t mode; + uint16_t __spare0[1]; + uint64_t ino; + uint64_t size; + uint64_t blocks; + uint64_t attributes_mask; + struct fuse_sx_time atime; + struct fuse_sx_time btime; + struct fuse_sx_time ctime; + struct fuse_sx_time mtime; + uint32_t rdev_major; + uint32_t rdev_minor; + uint32_t dev_major; + uint32_t dev_minor; + uint64_t __spare2[14]; +}; + struct fuse_kstatfs { uint64_t blocks; uint64_t bfree; @@ -581,6 +616,7 @@ enum fuse_opcode { FUSE_REMOVEMAPPING = 49, FUSE_SYNCFS = 50, FUSE_TMPFILE = 51, + FUSE_STATX = 52, /* CUSE specific operations */ CUSE_INIT = 4096, @@ -645,6 +681,22 @@ struct fuse_attr_out { struct fuse_attr attr; }; +struct fuse_statx_in { + uint32_t getattr_flags; + uint32_t reserved; + uint64_t fh; + uint32_t sx_flags; + uint32_t sx_mask; +}; + +struct fuse_statx_out { + uint64_t attr_valid; /* Cache timeout for the attributes */ + uint32_t attr_valid_nsec; + uint32_t flags; + uint64_t spare[2]; + struct fuse_statx stat; +}; + #define FUSE_COMPAT_MKNOD_IN_SIZE 8 struct fuse_mknod_in { -- GitLab From 9dc10a54abe50b733a5b561d5f8be718e79c3590 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 10 Aug 2023 12:45:05 +0200 Subject: [PATCH 1145/3445] fuse: add ATTR_TIMEOUT macro Next patch will introduce yet another type attribute reply. Add a macro that can handle attribute timeouts for all of the structs. Signed-off-by: Miklos Szeredi --- fs/fuse/dir.c | 26 ++++++++------------------ fs/fuse/fuse_i.h | 5 ++++- fs/fuse/readdir.c | 4 ++-- 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index d38ab93e20077..04006db6e1732 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -92,7 +92,7 @@ static void fuse_dentry_settime(struct dentry *dentry, u64 time) /* * Calculate the time in jiffies until a dentry/attributes are valid */ -static u64 time_to_jiffies(u64 sec, u32 nsec) +u64 fuse_time_to_jiffies(u64 sec, u32 nsec) { if (sec || nsec) { struct timespec64 ts = { @@ -112,17 +112,7 @@ static u64 time_to_jiffies(u64 sec, u32 nsec) void fuse_change_entry_timeout(struct dentry *entry, struct fuse_entry_out *o) { fuse_dentry_settime(entry, - time_to_jiffies(o->entry_valid, o->entry_valid_nsec)); -} - -static u64 attr_timeout(struct fuse_attr_out *o) -{ - return time_to_jiffies(o->attr_valid, o->attr_valid_nsec); -} - -u64 entry_attr_timeout(struct fuse_entry_out *o) -{ - return time_to_jiffies(o->attr_valid, o->attr_valid_nsec); + fuse_time_to_jiffies(o->entry_valid, o->entry_valid_nsec)); } void fuse_invalidate_attr_mask(struct inode *inode, u32 mask) @@ -266,7 +256,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) forget_all_cached_acls(inode); fuse_change_attributes(inode, &outarg.attr, - entry_attr_timeout(&outarg), + ATTR_TIMEOUT(&outarg), attr_version); fuse_change_entry_timeout(entry, &outarg); } else if (inode) { @@ -399,7 +389,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name goto out_put_forget; *inode = fuse_iget(sb, outarg->nodeid, outarg->generation, - &outarg->attr, entry_attr_timeout(outarg), + &outarg->attr, ATTR_TIMEOUT(outarg), attr_version); err = -ENOMEM; if (!*inode) { @@ -686,7 +676,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, ff->nodeid = outentry.nodeid; ff->open_flags = outopen.open_flags; inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, - &outentry.attr, entry_attr_timeout(&outentry), 0); + &outentry.attr, ATTR_TIMEOUT(&outentry), 0); if (!inode) { flags &= ~(O_CREAT | O_EXCL | O_TRUNC); fuse_sync_release(NULL, ff, flags); @@ -813,7 +803,7 @@ static int create_new_entry(struct fuse_mount *fm, struct fuse_args *args, goto out_put_forget_req; inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, - &outarg.attr, entry_attr_timeout(&outarg), 0); + &outarg.attr, ATTR_TIMEOUT(&outarg), 0); if (!inode) { fuse_queue_forget(fm->fc, forget, outarg.nodeid, 1); return -ENOMEM; @@ -1190,7 +1180,7 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat, err = -EIO; } else { fuse_change_attributes(inode, &outarg.attr, - attr_timeout(&outarg), + ATTR_TIMEOUT(&outarg), attr_version); if (stat) fuse_fillattr(inode, &outarg.attr, stat); @@ -1867,7 +1857,7 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr, } fuse_change_attributes_common(inode, &outarg.attr, - attr_timeout(&outarg), + ATTR_TIMEOUT(&outarg), fuse_get_cache_mask(inode)); oldsize = inode->i_size; /* see the comment in fuse_change_attributes() */ diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index d830c2360aefd..cfb97a147b66e 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1114,7 +1114,10 @@ void fuse_invalidate_entry_cache(struct dentry *entry); void fuse_invalidate_atime(struct inode *inode); -u64 entry_attr_timeout(struct fuse_entry_out *o); +u64 fuse_time_to_jiffies(u64 sec, u32 nsec); +#define ATTR_TIMEOUT(o) \ + fuse_time_to_jiffies((o)->attr_valid, (o)->attr_valid_nsec) + void fuse_change_entry_timeout(struct dentry *entry, struct fuse_entry_out *o); /** diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c index b3d498163f973..c58447be5e4dc 100644 --- a/fs/fuse/readdir.c +++ b/fs/fuse/readdir.c @@ -224,7 +224,7 @@ retry: forget_all_cached_acls(inode); fuse_change_attributes(inode, &o->attr, - entry_attr_timeout(o), + ATTR_TIMEOUT(o), attr_version); /* * The other branch comes via fuse_iget() @@ -232,7 +232,7 @@ retry: */ } else { inode = fuse_iget(dir->i_sb, o->nodeid, o->generation, - &o->attr, entry_attr_timeout(o), + &o->attr, ATTR_TIMEOUT(o), attr_version); if (!inode) inode = ERR_PTR(-ENOMEM); -- GitLab From a1ef3aaf6ada374818ebcf978c175e65a4cd60ab Mon Sep 17 00:00:00 2001 From: Changbin Du Date: Tue, 18 Jul 2023 16:52:42 +0800 Subject: [PATCH 1146/3445] perf docs: Fix format of unordered lists Fix the format of unordered lists so the can wrap properly. Signed-off-by: Changbin Du Acked-by: Adrian Hunter Cc: Alexander Shishkin Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20230718085242.3090797-1-changbin.du@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-ftrace.txt | 16 +++--- tools/perf/Documentation/perf-record.txt | 73 +++++++++++++----------- 2 files changed, 48 insertions(+), 41 deletions(-) diff --git a/tools/perf/Documentation/perf-ftrace.txt b/tools/perf/Documentation/perf-ftrace.txt index df4595563801e..d780b93fcf871 100644 --- a/tools/perf/Documentation/perf-ftrace.txt +++ b/tools/perf/Documentation/perf-ftrace.txt @@ -96,8 +96,9 @@ OPTIONS for 'perf ftrace trace' --func-opts:: List of options allowed to set: - call-graph - Display kernel stack trace for function tracer. - irq-info - Display irq context info for function tracer. + + - call-graph - Display kernel stack trace for function tracer. + - irq-info - Display irq context info for function tracer. -G:: --graph-funcs=:: @@ -118,11 +119,12 @@ OPTIONS for 'perf ftrace trace' --graph-opts:: List of options allowed to set: - nosleep-time - Measure on-CPU time only for function_graph tracer. - noirqs - Ignore functions that happen inside interrupt. - verbose - Show process names, PIDs, timestamps, etc. - thresh= - Setup trace duration threshold in microseconds. - depth= - Set max depth for function graph tracer to follow. + + - nosleep-time - Measure on-CPU time only for function_graph tracer. + - noirqs - Ignore functions that happen inside interrupt. + - verbose - Show process names, PIDs, timestamps, etc. + - thresh= - Setup trace duration threshold in microseconds. + - depth= - Set max depth for function graph tracer to follow. OPTIONS for 'perf ftrace latency' diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 7d362407fb39e..d5217be012d79 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -509,9 +509,10 @@ CLOCK_BOOTTIME, CLOCK_REALTIME and CLOCK_TAI. Select AUX area tracing Snapshot Mode. This option is valid only with an AUX area tracing event. Optionally, certain snapshot capturing parameters can be specified in a string that follows this option: - 'e': take one last snapshot on exit; guarantees that there is at least one + + - 'e': take one last snapshot on exit; guarantees that there is at least one snapshot in the output file; - : if the PMU supports this, specify the desired snapshot size. + - : if the PMU supports this, specify the desired snapshot size. In Snapshot Mode trace data is captured only when signal SIGUSR2 is received and on exit if the above 'e' option is given. @@ -550,8 +551,9 @@ providing implementation for Posix AIO API. --affinity=mode:: Set affinity mask of trace reading thread according to the policy defined by 'mode' value: - node - thread affinity mask is set to NUMA node cpu mask of the processed mmap buffer - cpu - thread affinity mask is set to cpu of the processed mmap buffer + + - node - thread affinity mask is set to NUMA node cpu mask of the processed mmap buffer + - cpu - thread affinity mask is set to cpu of the processed mmap buffer --mmap-flush=number:: @@ -603,16 +605,17 @@ Record timestamp boundary (time of first/last samples). --switch-output[=mode]:: Generate multiple perf.data files, timestamp prefixed, switching to a new one based on 'mode' value: - "signal" - when receiving a SIGUSR2 (default value) or - - when reaching the size threshold, size is expected to - be a number with appended unit character - B/K/M/G -